What Does Redux Do? (and when should you use it?)

By Dave Ceddia

Struggling to wrap your head around Redux? Don’t worry, you’re not alone.

I’ve heard from many, many people that Redux is the biggest barrier to writing the React apps they want to.

By the end of this post you’ll understand what Redux is for, and how to know when it’s time to add it to your own app.

Why?

The best question to start with is, Why should we use Redux at all?

And the answer isn’t “because everyone else on the internet is using it.” (I don’t doubt that’s why a lot of people are using it, but let’s go deeper.)

The reason Redux is useful is that it solves a problem.

And no, the problem it solves is not “state management.” That’s super vague. Heck, React already does state management. Redux does help manage state, but that’s not the problem it solves.

It’s About Data Flow

If you’ve used React for more than a few minutes, you probably know about props and one-way data flow. Data is passed down the component tree via props. Given a component like this:

Counter component

The count, stored in App’s state, would be passed down as a prop:

Passing props down

For data to come back up the tree, it needs to flow through a callback function, so that callback function must be passed down to any components that want to pass data up.

Passing callbacks down

You can think of the data like electricity, connected by colored wires to the components that care about it. Data flows down and up through these wires, but the wires can’t be run through thin air – they have to be connected between each component in the tree.

This is all review, hopefully. (If not, you should stop here, go learn React, build a couple small apps, and come back in a few days. Seriously. Redux is gonna make no sense until you understand how React works.).

Layers and Layers of Data Flow

Sooner or later you run into a situation where a top-level container has some data, and a child 4 levels down needs that data. Here’s a screenshot of Twitter, with all the avatars highlighted:

Twitter user data

Let’s say the user’s avatar is stored as part of their profile data, and the top-level App component holds the user. In order to deliver the user data to the all 3 Avatar components, the user needs to be woven through a bunch of intermediate components that don’t need the data.

Sending the user data down to the Avatar components

Getting the data down there is like threading a needle through a mining expedition. Wait that doesn’t make any sense. Anyway, it’s a pain in the ass.

More than that, it’s not very good software design. Intermediate components in the chain must accept and pass along props that they don’t care about. This means refactoring and reusing components from that chain will be harder than it needs to be.

Wouldn’t it be nice if the components that didn’t need the data didn’t have to see it at all?

Plug Any Data Into Any Component

This is the problem that Redux solves. It gives components direct access to the data they need.

Using the connect function that comes with Redux, you can plug any component into Redux’s data store, and the component can pull out the data it requires.

Connecting Redux to the Avatar components

This is Redux’s raison d’etre.

Yeah, it also does some other cool stuff too, like make debugging easier (Redux DevTools let you inspect every single state change), time-travel debugging (you can roll back state changes and see how your app looked in the past), and it can make your code more maintainable in the long run. It’ll teach you more about functional programming too.

But this thing here, “plug any data into any component,” is the main event. If you don’t need that, you probably don’t need Redux.

The Avatar Component

To tie all this back to code, here’s an example of the Avatar component from above:

import React from 'react';
import { connect } from 'react-redux';

const Avatar = ({ user }) => (
  <img src={user.avatar}/>
);

const mapStateToProps = state => ({
  user: state.user
});

export { Avatar };
export default connect(mapStateToProps)(Avatar);

The component itself doesn’t know about Redux – it just accepts a user prop and renders the avatar image. The mapStateToProps function extracts the user from Redux’s store and maps it to the user prop. Finally, the connect function is what actually feeds the data from Redux through mapStateToProps and into Avatar.

You’ll notice there are two exports at the end – a named one, and a default. This isn’t strictly necessary, but it can be useful to have access to the raw component and the Redux-wrapped version of it.

The raw component is useful to have when writing unit tests, and can also increase reusability. For example, part of the app might want to render an Avatar for another user other than the signed-in user. In that case, you could even go a step further and export the Redux-connected version as CurrentUserAvatar to make the code clearer.

When To Add Redux

If you have a component structure like the one above – where props are being forwarded down through many layers – consider using Redux.

If you need to cache data between views – for instance, loading data when the user clicks on a detail page, and remembering the data so the next access is fast – consider storing that data in Redux.

If your app will be large, maintaining vast data, related and not – consider using Redux. But also consider starting without it, and adding it when you run into a situation where it will help.

Up Next

Read Part 2 of this series where we’ll dive into the details of Redux: how to set it up, and how the important pieces fit together (actions and reducers and stores oh my!).

Translations

You can read this in Russian thanks to translation by howtorecover.me.