loading...
Cover image for Container vs. Presentational Components in React Redux

Container vs. Presentational Components in React Redux

notfocaccia profile image Alicia Fasciocco Originally published at Medium ・3 min read

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!

Posted on by:

notfocaccia profile

Alicia Fasciocco

@notfocaccia

Mostly remote HR Business Partner. Flatiron School Student. Collage Artist. A person with an early bedtime. she/her

Discussion

markdown guide