Make small React components

Sunday, May 21 2017 in react frontend

The more I experiment with React, the more I find small presentational components are the way to go. Take this markup for a panel component:

function Panel({ title, subtitle, doSomething }) {
  return (
  <div className="panel">
    <h2 className="panel__title">{title}</h2>
    <img src="some/url"/>
     <div panel__content>
      <h3 className="panel__subtitle">{subtitle}</h3>
     </div>
      <button class="action-button" onClick={doSomething}>Click me</button>
   </div>
 );
} 

Even though the Panel component looks small enough, it still defines a lot of its appearance in terms of bare HTML.

You should often strive for this instead:

function Panel({ title, subtitle, doSomething }) {
  return (
    <Box vertical>
      <Title>{title}</Title>
      <Image>
      <Box horizontal>
        <Subtitle>{subtitle}</Subtitle>
      </Box>
      <ActionButton onClick={doSomething}>Click me</ActionButton>
    </Box>
  );
}

Define a small component for every individual UI element. For example, SubTitle would be:

function SubTitle({ children }) {
  return <h3 className="panel__subtitle">children</h3>;
}

What makes defining these small components worthwhile?

  1. Readability: smaller components let their names explain what each element does. You need to inspect the markup less.
  2. Consistency: it’s likely that your user interface has some repeating patterns. You can re-use the same small component that combines markup and style to output the same visual elements.
  3. Isolation: small components make few assumptions about their surroundings; so, they interact predictably with them. You can keep them unaltered if you change state management solution: from setState() to Redux, for example. Harry Roberts tweeted a great insight. Isolation is beneficial even if reuse is limited.

CSS-in-JS makes it even more explicit that the goal of this component is just formatting (in this case Fela):

createComponent(() => {
  fontSize: '1.25rem',
  marginTop: '1rem',
}, 'h3');

The con is that small components make your element hierarchy deeper, which slows down renders. To counter that, pull elements up the hierarchy and remove superfluous grouping elements. Compose the UI with many small presentational components directly inside the component that handles the logic. For example, to display a list of employees in panels, you might be tempted to create an EmployeeList component:

class SmartComponent extends React.Component {
  render() {
    return <EmployeeList employees={this.state.employees}/>
  }
}

Instead, build the list directly inside the smart component:

class SmartComponent extends React.Component {
  render() {
    const employeePanels = employees.map(employee => <Panel title={employee.name}} subtitle={employee.job}/>);
    return (
      <ul class="employees">
       {employeePanels}
      </ul>
    );
}

The intent is even clearer as you don’t need to look inside the EmployeeList component to understand what’s going on. Try to build a small library of presentational components for use in your application. It will make the code more readable and reduce styling headaches.