Redux Fundamentals: using Redux with React (part one)

In my last post I highlighted how to create and use a Redux store. That was really the last important detail about Redux itself that we needed to cover before getting into how to use Redux in an actual React app.

I think it's worth noting that, while Redux works extremely well with React, it is built to be a completely generic library for managing application state. It could be—and has been—used to manage state with other tools like Backbone, Vue and Angular, to great success! Understanding that only helps to underscore just how simple and powerful Redux is.

Given that, Redux and React is a natural pairing, so let's talk about how to integrate the two.

Once you have a Redux store, the main challenge is understanding how to provide the current state of the store to a React component so that state can be rendered, and how to dispatch actions from React components back to the Redux store.

Creating container components

In a React app, we want most of our components to be purely presentational. That means that we really only want a few top-level components that collect and organize data before passing it down to smaller, simpler components that are only concerned with rendering parts of our UI correctly.

In Redux, these top-level components that collect and distribute data are called "container components." When all of our app's state is stored in a Redux store, we use the library react-redux to create these container components. Specifically, we use a function called connect that lets us sort through an entire store, pick out the data we care about, and pass it along to our presentational components as props:

import { connect } from 'react-redux';
import MyTopLevelComponent from './my-top-level-component';

const MyTopLevelContainer = connect()(MyTopLevelComponent);

export default MyTopLevelContainer;

This doesn't seem like it's doing anything to actually select and pass down data yet, because it's not. In order to do that, we pass an argument to connect that takes a store and transforms it into an object. This argument is a function that we call mapStateToProps:

const mapStateToProps = state => {
    return {
        username: state.username,
        isLoggedIn: state.isLoggedIn,
    };
};

const myTopLevelContainer = connect(mapStateToProps)(MyTopLevelComponent);

(Aside: you may be wondering why we call connect with two sets of parenthesis. For our purposes, this is just an implementation detail of react-redux, but if you're interested, you can read about higher-order components for more context.)

This takes the current state of our Redux store, pulls out the properties it cares about (state.username and state.isLoggedIn) and passes them to MyTopLevelComponent as to props, username and isLoggedIn.

This example mapStateToProps function is very simple, but you could do all sorts of things here, like creating new props that are calculations on or combinations of multiple bits of state. If you had a store with values numberOfApples and costPerApple, you could write a mapStateToProps function that includes both of those as props, but also a third prop valueOfApples to display the total value of your apple inventory:

const mapStateToProps = state => {
    const { numberOfApples, costPerApple } = state;
    const valueOfApples = numberOfApples * costPerApple;
    return { numberOfApples, costPerApple, valueOfApples };
};

Passing your store to your React app

Now we just need a way to tell our root React component where our actual store is, since it is a singleton that is only instantiated once universally.

react-redux gives us a way to do that with its Provider component. This component gets wrapped around your app's root React component that you render to the page with react-dom.

import { render } from 'react-dom';
import { Provider } from 'react-redux';
import MyTopLevelContainer from './my-top-level-container';
import myReduxStore from './my-redux-store';

const App = () => <div id="my-app"><MyTopLevelContainer /></div>;

render(
    <Provider store={myReduxStore}><App /></Provider>,
    document.getElementById('main')
);

Now Provider and your container component will receive state from your Redux store. Behind the scenes, react-redux even handles the subscribe logic for us that I talked about in my last post, so as the store's state changes, it will automatically tell our React app to re-render. Very convenient!

That's a lot to absorb, so we'll leave it at this for today. Next time: we'll finish up connecting Redux to our React app by establishing how to have React components dispatch actions to a store, so that we have a fully functional front-end application.