React: Functional, Class, and Pure Components

Image by Markus Winkler.

A good React app is built through building up standalone components, with modular development in mind. In fact, the biggest proponent and inventor of React Facebook makes use of over 30,000 components to build its UI and provide functionality to users.

One of the main concepts behind successful and efficient React development is reusable components that you can swap in and out, a little like LEGO pieces. In a similar way to having a separation between presentation and structure when developing with CSS and HTML, it's a great idea to keep your functional React logic far, far away from the components that render the UI for your users.

However, there are a few options for separating logic and rendering when it comes to React and optimising React involves picking the right component type for the job. So, what are your options, and when should you use them?

Photograph of a set of electrical components laid out on a table by Robin Glauser on Unsplash.

What are Class Components?

Class components were once the standard way to give a component local state and lifecycle methods. They receive props and may own state, but a class is not necessarily stateful: it can also render entirely from its props.

For example, a simple component defined using an ES6 class:

class HellowWorld extends React.Component {  render() {    return <p>Hello, {this.props.planet}</p>;  }}

A class component might fetch information and update local state through its lifecycle methods. That was the established model before Hooks, but the class syntax does not make the component inherently heavy; the cost depends on the work performed, its render tree and how often updates occur.


When Should You Use a Functional Component?

Function components are functions that return React elements. Since Hooks arrived in React 16.8, they can own state, run effects and compose reusable logic; "stateless" describes a particular component, not the functioncomponent category.

In simplest terms, and in its simplest form, a functional component just outputs some markup. For example:

function App() {  const greeting = 'Hello World';  return <p>{greeting}</p>;}

A function component is a good fit for a ListItem that renders from props within a List component, and Hooks allow the same form to grow when it genuinely needs state or an effect. It normally renders when its parent renders and can also render for its own state or context updates; the syntax does not prevent those updates.

Photograph of a set of electrical components offset to the lefthand side and laid out on a table by Robin Glauser on Unsplash.

How Should You Use Pure Components?

React.PureComponent is a class optimisation for a specific case. A normal function component and a normal class component both render when their parent renders. PureComponent may skip a class render when shallow comparison finds its props and state unchanged; React.memo provides a related option for function components.

React.PureComponent implements a shallow comparison of both props and state in shouldComponentUpdate. It still supports the class lifecycle; extending it does not make a component functionally pure or automatically faster. The comparison is worthwhile only when the skipped rendering costs more than the comparison and the data follows immutable update patterns.

class PureHelloWorld extends React.PureComponent {  render() {    const { hello, world } = this.props;    return (      <p>{hello} {world}</p>    )  }}

The shallow comparison checks toplevel references. Nested data is still passed and used, but mutating it in place can leave the toplevel reference unchanged and cause PureComponent to skip a needed render. Replace changed objects and arrays rather than mutating them.

Photograph of a set of electrical components offset to the right-hand side and laid out on a table by Robin Glauser on Unsplash.

Wrapping Up

Although it can be clear when to use a functional component vs. when to use something more lightweight, it can sometimes be tricky to determine whether you'd benefit more from using a functional component or a pure component.

Choose a function or class component for its API and maintenance context, not because one is intrinsically pure. A ListItem that always renders the same output for the same inputs is a candidate for memoisation, but add PureComponent or React.memo only after identifying avoidable renders and keep prop references stable enough for shallow comparison to be meaningful.


Planning a platform change?

I help teams make difficult platform work clearer, from architecture decisions and migrations to launch recovery, performance, and search visibility.