Container vs Presentational Components in React

The main thing to keep in mind is that container components and presentational components go together when setting up a React app component hierarchy. React apps will almost always need some components that take responsibility for the way things work, and components for displaying actual data. Where presentational components don’t manage state, container components do. Where presentational components are usually children in the app component hierarchy, container components are usually the parents of presentational components.

What are container components?

  • Container components are primarily concerned with how things work
  • they rarely have any HTML tags of their own, aside from a wrapping <div>
  • they are often stateful
  • they are responsible for providing data and behavior to their children (usually presentational components)

Here is an example of a container component:

class Collage extends Component {
constructor(props) {
super(props);

this.state = {
images: []
};
}
   componentDidMount() {
fetch('/api/current_user/image_list')
.then(response => response.json())
.then(images => this.setState({images}));
}
   render() {
return (
<div className="image-list">
{this.state.images.map(image => {
<div className="image">
<img src={book.image_url} />
</div>
})}
</div>
)
}
}

In contrast, what are presentational components?

  • Presentational Components are primarily concerned with how things look
  • probably only contain a render method and little else logic
  • they do not know how to load or alter the data that they render
  • they are best written as stateless functional components

Here is an example of a presentational component:

//defining the component as a React Component
class Image extends Component {
render() {
return <img src={this.props.image} />;
}
}
export default Image

//defining the component as a constant
const Image = props => (
<img src={props.image} />
)
export default Image

With presentational components, you have the option to define them like regular react components or as constants. Defining them as constants might help remove some dependencies and importing extra lines of code. So, in this way, defining presentational components as constants can cut down on app load time if you have lots of data to load.

Separation of concerns using a container component

Luckily, using React, we have the ability to compose our UI out of multiple React components. Keeping this in mind, we can separate the above container component example into into two components. First, we’d separate the UI layer into a presentational component. Then, we’d wrap that presentational component in a larger container component which passes down props into presentational components as children. In this way, the container can then handle the state and any other app logic.

Here’s how this might look:

const Image = props => (
<img src={props.image} />
)
export default Image
class ImageContainer extends React.Component {
constructor() {
super();

this.state = {
images: []
};
}
   componentDidMount() {
fetch('/api/current_user/image_list')
.then(response => response.json())
.then(images => this.setState({images}));
}
   render() {
return (
<div className="image-list">
{this.state.images.map(image => {
<Image image={image}/>
})}
</div>
)
}
}
export default ImageContainer

To recap, we’ve broken up the original component into two pieces. All the state in contained in our container component ImageContainer, and our logic is still the same. The presentational component Image is stateless and is now incredible stable and concise. In this way, if the API data is changed (such as if src is changed to link) we would be able to make that update within a single presentational component that will update all of the children of that map function. This also allows us to render as many images as possible, since Image is now a reusable component in React. Always remember that reusable components are arguably one of the most powerful aspects of React, so it’s important to always keep that in mind when designing your app structure.