Container Components and Stateless Functional Components in React

In the article Building a Chat Component in React and ES6, we learned a way to create React components:

This simple component is written by extending React.Component.

We will now introduce another way to define simple components. You will not only write less code, but you will also benefit from performance optimizations done by React. Let's introduce functional components:

SimpleComponent has become a function with a props argument, returning the return value of the render method of the original implementation.

You can either use the ES6 arrow function syntax, or the regular ES5 function syntax. I personally prefer arrow functions, as they are more compact.

The functional syntax does not allow you to use component lifecycle methods. As you won't be able to use setState either, your component has to be stateless. This is where the name stateless functional component comes from.

Stateless functional components have no state. They get data exclusively from their props. They are typically used as dumb presentational components. As these components are simple, they encourage writing clean, testable code. Absence of state manipulation implies that you don't need mocking or external libraries to fully test them. After all, a stateless functional component does nothing else, but takes props, and returns the markup of the component.

Implications of the structure of stateless functional components:

  • little or no logic inside, they are fully about presentation,
  • they receive data and callbacks via props,
  • later, when we will use Redux, these components will have no knowledge of Redux

In the introduction, I mentioned that stateless functional components come with performance benefits. The absence of state manipulation and lifecycle methods enabled React core to implement some shortcuts. When stateful components perform expensive checks and memory allocations, stateless functional components do nothing.

Stateless functional components are managed by container components. Typically, container components have the following properties:

  • they are stateful,
  • their markup is minimal,
  • they pass data and callback methods down to their children as props
  • later, when we'll use Redux, container components will be connected to Redux

The rule of thumb for choosing the appropriate syntax for React components is the following:

Use classes for components with state. Use functions for stateless components whenever possible.

If your component

  • doesn't have to use component lifecycle methods,
  • doesn't have to manage its state,
  • doesn't have to perform any performance optimizations,
  • doesn't need refs to the underlying dom,
  • doesn't need child functions,

then it is advised to use stateless functional components. The last criterion needs some explanation. Whenever you render a component, all child functions are re-created. In order to avoid the performance tax of re-instantiating functions, use class components instead.

Transforming a simple React component into a functional component

Let's put theory into practice, and transform all the stateless component in our chat application into functional components. Recall the chat application introduced in this article.

Let's start with the MessageList class.

This is the most straightforward component you can possibly transfer into a functional component, as it does nothing else, but transfer its props into JSX.

For the transformation to work, you need to apply the following steps:

  • declare MessageList as a function accepting props as its argument
  • remove the render concise method wrapper, and keep the function body only to indicate the return value of the MessageList function
  • change this.props to props in the function body, as you will reference the input argument of the MessageList function

After these three steps, the result will look like this:

Rewriting the Message component works in the exact same way. The original code looks like this:

After the transformation, you get the following result:

What about components with callbacks?

Two stateless components are done, there are two more to go. Let's start with the ClearButton component.

You have learned almost everything to transfer this component into a function. There is just one difference: this component contains a handleClearMessages callback.

Reviewing the conditions for modeling a component with a function, we can see that there is absolutely nothing preventing us from creating a functional equivalent of the ClearButton class.

The question is, how can we model the callback?

Modeling is actually more straightforward than you would think. Just erase the constructor, and make the handleClearMessages callback as a nested function inside the function body. You don't need to worry about binding or the context anymore, as the function will be accessible to you inside the function.

The only problem with this approach is that the handler function is recreated each time the DOM is rendered.

Refs don't work in functional components

Regarding PostMessageForm, there is one more trick we need to apply: the handleSubmit event handler heavily relies on the component refs.

Unfortunately, there is no context where we can change the nameInput and messageInput refs. Often times this is an indication that we are better off keeping the component class-based. Furthermore, introducing state to the component may be beneficial: we can create a controlled component with all its benefits described in the article.

If we wish to keep our component functional, we have to introduce local variables for storing the referenced input values, and get rid of the this context in front of the refs.

Visit the reference solution by clicking this CodePen link. You can see that our application works in the exact same way as the one at the beginning of this article.

Hopefully you are now convinced that stateful functional components are easy to construct. As these components come with many benefits, including performance and testability, I highly recommend using them in your React applications.

Learn ES6 in Practice

Sign up below to access an ES6 course with many exercises and reference solutions.