Writing good React components

Moe Sattler
3 min readAug 25, 2016

In recent years, React has become one of the top choices for writing Single-Page Applications, not least because of its highly modular components.
It enables developers to break down UI in reusable, testable and simple units. To get the most out of this, you should follow some rules of thumb.

Keep it small

While this holds true for almost all things in software development, it is especially true for components. Huge components are not only hard to understand and reason about, they also make testing quite challenging.

Ideally, a component can be understood by quickly glancing over it and only does a single thing. This could be displaying some data or being a composition of other components, for instance, a form.

Avoid state when possible

State is the number one cause for overly complex components. Instead of just understanding what output a given input produces, a developer now has to think about what state a component is in, how it is mutated, and how it affects the output. In a component rich of state, testing might turn into a tedious task, where many state configurations have to be considered.

Use state the right way

State can’t always be avoided. Two things need to be considered, when thinking about putting something in a component’s state:

  1. Does this data really belong into state?

Facebook’s Dan Abramov gives a good answer:

2. Should I put the data into React’s state or somewhere external (e.g. a Store) ?

Usually, it is a good idea to keep state in stores, if it has global relevance or mutates in complex ways. If state is purely UI-related, not used anywhere else and has a shorter lifespan than the component itself, it probably belongs to the component’s own state.

Use functional components

If your component is free of internal state and lifecycle methods, it’s best to turn it into a functional component. Those kind of components are lightweight and produce exactly one output for any given input. They are easy to understand, easy to test and enforce good practices. It’s a good idea to start a new component functional, and only turn it into a class if it is really necessary.

Keep components reusable

“Program to an interface, not an implementation” holds very true for Components. To avoid complex “magic” and be able to reuse it, you should keep your components open for different use cases. Instead of hardcoding values or logic for one particular use case, consider letting props determine the components behavior.


const BananaShop = ({ onBuy }) => (
<div>
<img src="http://banana-picture.url" />
<p>Some delicious bananas</p>
<button onClick={() => onBuy()}>
Buy
</button>
</div>
)
// better
const ProductShop = ({ product }) => (
<div>
<img src={product.url} />
<p>{product.description}</p>
<button onClick={() => product.onBuy()}>
Buy
</button>
</div>
)
const BananaShop = ({ onBuy }) => {
const banana = {
url: 'http://banana-picture.url',
description: 'Some delicious bananas'
}
return (
<ProductShop product={banana} onBuy={() => onBuy('banana')}/>
)
}

Smart and dumb components

Dan Abramov has written an excellent article about smart and dumb components and when to use them. Dumb components are concerned with how things look and ideally just map props to DOM. Smart components, on the other hand, are concerned with data fetching and mutating. Try not to mix those two concerns.

PropValidation

Always write PropValidation as precise as you can. Don’t just validate that a prop is an object, validate if the object has the necessary properties. This way a user does not have checkout the source code if an invalid property has been passed, but the warning will state everything necessary.


const Coworker = ({ worker }) => (
<div>
<h1>{worker.id}</h1>
<span>{worker.name}</span>
<p>{worker.duties}</p>
</div>
)
// bad
const { object } = React.PropTypes
Coworker.propTypes = {
worker: object.isRequired
}
// better
const { shape, number, string, arrayOf } = React.PropTypes
Coworker.propTypes = {
worker: shape({
id: number.isRequired,
name: string,
duties: arrayOf(string)
}).isRequired
}

Hopefully…

…if you follow those basic principles, you will be able to realize that your code quality will increase quite a bit, and other people will enjoy using and working with your components.

Find me on Twitter and Github :)

--

--