The Container Pattern in React

1. Overview

This is a quick introduction to the container pattern in React.

2. Container Pattern

First of all, we can say that the container pattern is a simple React pattern. Most noteworthy mentioning is that here the components are divided into:

  • the presentation part and
  • the container part.

Previously, React was considered by many the V part in the MVC paradigm. However, nowadays we have overcome this belief. In contrast, we can say that in MVC language the presentation part would be the View, while the container part would be the Controller.

In essence, the main benefits of this container pattern are the separation of concerns and the reusability of code.

2. The Presentation Component

Let’s highlight the key features of the presentation components are:

  • mainly concerned with the presentation part,
  • ideally written as functional components unless a hook or state needs to be defined,
  • ideally stateless but can have states mainly concerning the UI,
  • unaware of how data is modified and use props for callbacks and to retrieve data.

3. The Container Component

In contrast with the presentation child component, container components are:

  • mainly concerned with the functionality,
  • using presentation subcomponents for the view part,
  • passing and managing data shown in the presentation subcomponents,
  • often stateful.

4. Example

In this example, we want to display a list of recipes. In particular, each recipe has a corresponding image. Subsequently, on clicking on any image, we should direct the user to a details screen.

4.1. RecipeList

Here, we create the TypeScript file RecipeList to render the recipe list on the screen.

In this case, we are using a lambda functional component accepting props as a parameter. Specifically, we need the parent component (the container component) to pass:

  1. the recipes,
  2. a function navigateToRecipeDetailsPass event handler. This is called whenever any recipe related image is clicked.
interface Props {
  navigateToRecipeDetails: (tileLabel: string)=>void;
  recipes: Array<Recipe>,
}

const RecipeList = (props: Props)=> {
  return (
      <div>
        {
          props.recipes.map((tile,idx) => (
          <div key={idx} onClick={()=>props.navigateToRecipeDetails(tile.label)}>
            <Card>
              <CardMedia>
                <img src={tile.image} />
              </CardMedia>
            </Card>
          </div>
        ))}
      </div>
    );
};

export default RecipeList;

4.2. RecipeListContainer

Now, we need to create the parent container RecipeListContainer component. Mainly, this will take care of passing the recipes to and also a function navigateToRecipeDetails to its child component.

interface Props {
  navigateToRecipeDetails: (tileLabel: string)=>void;
  recipes: Array<Recipe>,
}

const RecipesListContainer = (props: Props)=> {
  return (
      <RecipesList recipes={props.recipes} navigateToRecipeDetails={props.navigateToRecipeDetails}/>
  );
};

export default RecipesListContainer;

5. Conclusion

Seems like I have become big fan of this container pattern. Hence, I really suggest trying it out as soon as possible.

Now, let’s list what we have accomplished in this post.

Firstly, we have first created a reusable component RecipeList.

Additionally, we have also created a container component RecipeListComponent which calls its child RecipeList for rendering purposes.

In conclusion, the most important thing that we have learned is how to make our code more readable by separating concerns. As a result, we have separated the presentation part from the data functional part.

Photo by Markus Spiske from Pexels

Share this:

Leave a Reply

Your email address will not be published. Required fields are marked *