Skip to content
Logo Theodo

How to write the perfect React component (a Theodo standard)

Clément Pasteau5 min read

What is the perfect React component?

How to create the perfect React component?

  1. Logic Functions
  2. Atomic Design
  3. Selectors and Reselectors
  4. Functions inside render

Logic Functions

Bad Example

// MyComponent.js
export default class MyComponent extends PureComponent {
   computeAndDoStuff = prop1, prop2 => {
      // Logic that returns something depending on the props passed
   }

   render() {
      <div>
         {this.computeAndDoStuff(this.props.prop1, this.props.prop2) && <span>Hello</span>}
      </div>
   }
}

MyComponent.propTypes = {
   prop1,
   prop2,
}

const mapStateToProps = state => {
   prop1: state.object.prop1,
   prop2: state.object.prop2,
}

export const MyComponentContainer = connect(mapStateToProps)(MyComponent)

Good Example

// MyComponent.js
import { computeAndDoStuff } from '@services/computingService'

export default class MyComponent extends PureComponent {
   render() {
      <div>
         {computeAndDoStuff(this.props.prop1, this.props.prop2) && <span>Hello</span>}
      </div>
   }
}

MyComponent.propTypes = {
   prop1,
   prop2,
}

const mapStateToProps = state => {
   prop1: state.object.prop1,
   prop2: state.object.prop2,
}

export const MyComponentContainer = connect(mapStateToProps)(MyComponent)

// computingService.js
export computeAndDoStuff = prop1, prop2 => {
   // Logic that returns something depending on the props passed
}

Atomic Design

Bad Example

// MyPage.js
import { MyComponent1, MyComponent2, MyField1, Myfield2 } from '@components'

export default class MyPage extends PureComponent {
   render() {
      <div>
         <MyComponent1 />
         <div>
            <MyField1 />
            <MyField2 />
            <MyField1 disabled />
            <MyField2 color={'blue'} />
         </div>
         <MyComponent2 />
      </div>
   }
}

export const MyPageContainer = connect(mapStateToProps)(MyPage)

Good Example

// MyPage.js
import { MyOrganism1, MyOrganism2, MyOrganism3 } from '@organisms'

export default class MyPage extends PureComponent {
  render() {
     <div>
        <MyOrganism1 />
        <MyOrganism2 />
        <MyOrganism3 />
     </div>
  }
}

// MyOrganism1.js
import { MyMolecule1, MyMolecule2 } from '@molecules'

export default class MyOrganism1 extends PureComponent {
  render() {
     <div>
        <MyMolecule1 />
        <MyMolecule2 />
     </div>
  }
}

// MyMolecule1.js
import { MyAtom1, MyAtom2 } from '@atoms'

export default class MyMolecule1 extends PureComponent {
  render() {
     <div>
        <MyAtom1 />
        <MyAtom2 />
     </div>
  }
}

Selectors and Reselectors

Bad Example

// Table.js
import ...

export default class Table extends PureComponent {
   constructor(props) {
      super(props)
      this.renderTable = this.renderTable.bind(this)
      this.calculateNewProps(...props)
   }
   
   componentWillUpdate(nextProps) {
      this.calculateNewProps(...nextProps)
   }
   
   calculateNewProps = (prop1, prop2, ..., prop15) => {
      // Logic that modifies the store for the table rendering
   }
   
   renderTable() {
      // Return JSX based on props
   }

   render() {
      this.renderTable()
   }
}

Table.propTypes = {
   prop1,
   prop2,
   ...
   prop15,
}

const mapStateToProps = state => {
   prop1: state.object.prop1, 
   prop2: state.object.prop2,
   ...
   prop15: state.object.prop15,
}

export const TableContainer = connect(mapStateToProps)(Table)

Good Example

// Table.js
import ...
import { getTableRows } from '@selectors'

export default class Table extends PureComponent {
   renderTable() {
      // Return JSX based on rows
   }

   render() {
      this.renderTable()
   }
}

Table.propTypes = {
   tableRows,
}

const mapStateToProps = state => {
   tableRows: getTableRows(state),
}

export const TableContainer = connect(mapStateToProps)(Table)

// selectors.js
import { createSelector } from 'reselect'

export const getTableRows = createSelector(
   getProp1,
   getProp2,
   ...,
   getProp15,
   (prop1, prop2, ..., prop15) => {
      // logic to return the table rows based on the props in the store
   }
)

Functions inside render

Bad Example

// MyPage.js
import doSomething from '@services'

export default class MyPage extends PureComponent {
   render() {
      <div>
         <Button onClick={() => doSomething(this.props.param))} />
      </div>
   }
}

MyPage.propTypes = {
   param,
}

Good Example

// MyPage.js
import doSomething from '@services'

export default class MyPage extends PureComponent {
   onClick = () => doSomething(this.props.param)

   render() {
      <div>
         <Button onClick={this.onClick} />
      </div>
   }
}

MyPage

Liked this article?