Quick Links

React has a component-based architecture that encourages you to split your codebase into reusable units of functionality. Not all components are created equal though. Let's look at the differences between two common types, Presentational and Container (also known as "Stateful") components.

Is There Any State?

To begin with, it should be stressed that these terms don't refer to any specific React feature. They describe a style of writing React components which helps to maintain modularity and separate out concerns. The existence of the two component types arises from choices made in your codebase.

There's only one distinguishing factor: container components have state and presentational components do not. In practice, this means that a container component always makes a call to React's

        setState()
    

method. A presentational component will never make use of state.

Looking at Examples

Here's a simple presentational component:

import React from "react";
    

class Presentational extends React.Component {

render() {

return <h1>{this.props.title}</h1>;

}

}

export default Presentational;

The component is extremely simple. It renders a single

        h1
    

tag which displays text passed into the component via its

        title
    

prop. Let's now look at a stateful container component:

import React from "react";
    

class Container extends React.Component {

constructor(props) {

super(props);

this.state = {

time: (new Date()).toString()

};

}

componentDidMount() {

setInterval(() => {

this.setState({time: (new Date()).toString()});

}, 1000);

}

render() {

return <h1>{this.state.time}</h1>;

}

}

export default Container;

The container component's

        render
    

method is almost identical to that in the presentational component. The difference is the container component sources its text from inside itself, instead of relying on an outside value passed in as a prop.

Each second, the container component calls

        setState()
    

to update the

        time
    

key in its state. This causes React to re-render the component and display the new time. Our container possesses its own state.

Characteristics of Each Type

Several unique characteristics tend to arise within both presentational and container components. Looking at presentational components first, the bulk of their code is likely to exist within the

        render
    

method. They'll contain very little logic as their behaviour is defined by the outside world.

Presentational components are blissfully unaware of where their data is coming from. They don't know when (or whether) it will change. Some examples may not even accept props. Here's a decorational element which simply renders a specific image file:

    

        export () => <img src="/logo.png" />
    

Container components are much the opposite of their presentational counterparts. You'll typically find most of your site's logic ends up within a container component. The

        render
    

method may be comparatively short as you'll be spending many more lines fetching data from external sources, transforming it to suit your needs and then storing it into state.

A container component's

        render
    

method could consist of a single line that renders a presentational component. You've now got strong separation of concerns, with both components having a distinct role that fully respects the other's. The container component sources the data; the presentational component puts it on the screen.

Here's how this looks in practice:

import React from "react";
    

const View = ({title, body}) => (

<div>

<h1>{title}</h1>

<p>{body}</p>

</div>

);

class BlogPostComponent extends React.Component {

constructor(props) {

super(props);

this.state = {

blog: null

};

}

componentDidMount() {

fetch("/blog-post.json")

.then(response => response.json());

.then(blog => this.setState({blog}));

}

render() {

return (

<View

title={this.state.blog.headline}

body={this.state.blog.content} />

);

}

}}

        BlogPostComponent
    

is our container component. It loads a post over the network. The data then gets given to the

        View
    

component for rendering.

        View
    

doesn't care where it gets its data from - in the future, we could reuse it to display posts fetched from a third-party API such as Facebook or Twitter.

Container components are so called because they tend to encapsulate entire functional areas of your app. They make your project work and represent the app's backend systems.

In a real codebase,

        BlogPostComponent
    

would have even more responsibility. It would need to track whether the post has loaded and handle errors during the network fetch. Consequently, the

        render
    

method may incorporate some basic logic to alter what gets displayed - either an error message, a progress bar or our presentational

        View
    

component. Presentational components never have any greater responsibility than rendering a specific section of the UI into the DOM.

Advantages of Separating Presentational and Container Components

Using this pattern helps you to organise your codebase and prevents components from becoming too unwieldy. Although it's not a hard-and-fast rule, diligent separation of the two types improves maintainability as your project's component count grows.

Try to look for opportunities to refactor as a container component's

        render
    

method grows. It's likely you could take much of its contents and split it into a new presentational component. This makes it easier to reuse the presentational code in the future. It ends up self-contained and capable of operating independently of any specific data source.

Stateful components are less likely to be reused. Non-trivial behaviours naturally accumulate within them, resulting in dependencies on the outside world. That's not to say they can't be reused though - a two-stage confirmation button will contain internal state (to determine whether to display "Reset User's Password" or "Are You Sure?") but will also be deployed throughout your codebase.

Perhaps more than anything, intentionally distinguishing between Presentional and Container components keeps you aware of where your application's state lies. Minimising the number of components with state contributes towards a maintainable codebase and helps to separate concerns.

If you can't decide whether a component should hold state, keep coding and refactor later - it's probably too early in your project's lifecycle to know where the complexity (and hence the state) will congregate.