Container vs. Presentational Components in React Redux

Alicia Fasciocco
3 min readApr 25, 2020

--

Photo Credit: Nathan Myhrvold/ The Cooking Lab, LLC.

For the final project (!!!) at Flatiron School, we were asked to build a SPA app using React Redux with a Rails API. In the project planning phase, I thought about what was “sparking joy” in the time of the COVID pandemic. It seemed like there were quite a few answers, but the one that stood out most was food. Famous chefs were posting cooking videos to Instagram, good samaritans were donating pizzas to medical staff and essential workers, and it seemed like everyone and their brother was baking bread. That’s when I decided — I was going to make a recipe box app called BreadBox.

As I started making a flow chart version of my app, I realized I didn’t quite understand the difference between container and presentational components. Realizing you don’t know a concept is unnerving. (It’s around this time that you say to yourself, “I’m definitely going to fail this project.” But, there is a tiny voice in the very back of your brain that says, “You know you’ll find a way.” Listen to the tiny voice.) In an effort to understand, I broke it way down for myself by reading a few hundred resources.

Container Components:

  • Deal with managing data (typically state)
  • They often pass data to child components

Presentational Components:

  • Deal with how things look
  • Are often reusable

Let’s take a look at an example. As I was first building out my app, I had a single file that looked like this:

components/RecipeList.jsconst RecipeList = props => {    
const bread = require('../bread-default.jpg');
const recipeCards = props.recipes.length > 0 ? props.recipes.map(r => (
<div className="card" key={r.id}>
<Link to={`/recipes/${r.id}`}>
<h4>{r.attributes.label}</h4>
</Link>
<p><img src={r.attributes.image.length > 0 ? r.attributes.image : bread } width="300" height = "300" alt='bread'/></p><br/></div>)) : "You don't have any recipes yet!"
return recipeCards
}
const mapStateToProps = state => {
return {
recipes: state.userRecipes
}
}
export default connect(mapStateToProps)(RecipeList)

Woah — there is a lot going on here. We’re getting the data AND presenting it. It may work, but this file would be better parsed out, wouldn’t it? Let’s see what it looks like when we break it out into container and presentational components.

containers/RecipeList.jsconst RecipeList = props => (<div>
{props.recipes.map(recipe => (
<RecipeListCard
key={recipe.id}
recipe={recipe} />))
}
</div>
)
const mapStateToProps = state => {
return {
recipes: state.userRecipes
}
}
components/RecipeListCard.jsconst RecipeListCard = ({ recipe }) => (
<div className="card">
<Link to={`/recipes/${recipe.id}`}>
<h4>{recipe.attributes.label}</h4></Link>
<p><img src={recipe.attributes.image.length > 0 ? recipe.attributes.image : bread } width="300" height = "300" alt='bread'/></p><br/>
</div>
)

In the container component, we map over the current user’s recipes. We are able to do this by mapping state to props. mapStateToProps takes in the Redux store state and allows us to pick and choose what we’d like to use as a prop (or props) in the RecipeList component. In this case, we use our userRecipes, which returns only that user’s recipes.

Okay, so, we’ve mapped over our recipes, and now we are returning individual Recipe List Cards, which take in the deconstructed recipe. Since deconstruction is syntactic sugar from ES6 — we don’t have to say props.recipe.attributes.label, we can just say recipe.attributes.label, etc. I’ve also set a default image I’ve imported called ‘bread,’ in case the user doesn’t upload their own.

It works! Although it looks exactly the same to the user, the back-end has a little more room to breathe. I’ve also just unlocked the reusability factor of using containers. We could easily use the RecipeListCards component on another part of this app (or any app) if we wanted to.

Let’s recap!

  • Presentational components deal with how things look — they are often child components of parent containers. They are not usually stateful. They are reusable.
  • Container components deal with data collection (often from state). They usually pass that data down to child components.
  • Using them together is a powerful tool! Separation of concerns, amiright?

--

--

Alicia Fasciocco

software engineer | hr business partner | collage artist | in bed early