DEV Community

Cover image for Container vs. Presentational Components in React Redux
Alicia Fasciocco
Alicia Fasciocco

Posted on • Originally published at Medium

Container vs. Presentational Components in React Redux

Container vs. Presentational Components in React Redux first appeared on Medium.

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.js

const 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.js

const RecipeList = props => (
<div>
  {props.recipes.map(recipe => (
    <RecipeListCard
    key={recipe.id}
    recipe={recipe} />))
  }
</div>
)

const mapStateToProps = state => {
  return { 
    recipes: state.userRecipes
  }
}
components/RecipeListCard.js

const 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.

GitHub logo amfosh / bread-box

A SPA with React Redux & a Rails API. Store your favorite bread recipes to your very own BreadBox!

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay