Coupling Redux to React

In the first part of this introduction to Redux we talked about specific Redux things like actions, reducers and the store. So far we just applied these abstract things to our Silly App you probably know by now. However, nothing has been said about coupling Redux to React which is in fact the fun part since this will make the application do something.

After a short reminder of actions, reducers and the store I’ll jump into connecting Redux to React in this post.

Redux basics

Redux logoBasically everything a user of the app does triggers an action. An action is nothing more than a plain JS object with information about what happened. Sometimes additional data is sent along but this is not required. We implemented an action that only contains a type (this field is mandatory) to let the store know that the user clicked our button.

The store makes sure that the reducer is called with the current state and the action. Based on this input, the reducer returns a new state to the store. The store listens for state changes and consequently the views are rerendered.

Coupling Redux to React

There are two questions that come to mind when thinking about the coupling between React and Redux:

  1. How do we initialize the state of the application?
  2. How can we attach a Redux action to a React component, for example attaching it as an onClick callback?

The answer to these questions is a new concept: React components are divided in two categories: presentational components and container components. You already know the presentational components, these are just the React components that receive some props and render themselves based on these props.

Conceptually, a container component is a wrapper around a presentational component that talks to the store to connect Redux to React. Both the state and the actions are mapped to props and these are again passed to a presentational component. It should not come as a surprise that the react-redux package (available on npm) has a connect function to do exactly this.

In our Silly App we used to have the root component App. The state was initialized in this component and passed down to the child components. Consider the App component as the presentational component, our next step is to create the wrapper container component. We call it Main.

Mapping state to props

Let’s start with the mapping of the state. The state is stored in the store and when our app starts the state is initialised by calling the reducer once with the initial state. We specify the initial state in the reducer and after running the rootReducer function once, the state looks like this:

let state = {
    UI: {
        count: 0,
        view: 0
    },
    routing: {}
};

For now don’t bother about the routing part of the state, this part comes from the routerReducer that couples React Router to Redux.

What we are after is mapping the state above into a props object we can pass to the App component, we just want to be able to call this.props.count and this.props.view.

We should create a function mapStateToProps that takes the state and returns an object. This object will be accessible as this.props in the presentational components. In our example the function looks like this:

const mapStateToProps = function(state) {
    return {
        count: state.UI.count,
        view: state.UI.view
    };
};

Mapping actions to props

website-codeThe state is mapped to props, the next step is to do something similar with the actions. The key thing here is that we want to use the action creator, which is a function that returns the action object as an onClick callback in our presentation component so somehow we need to get this function in the props.

Redux has the bindActionCreators function available to help us out. If we create our action generators and make them exportable and we hook up bindActionCreators correctly, the actions are automatically dispatched once we use them from the props. It’s like magic!

So, in the example, our mapping function looks like this:

const mapDispatchToProps = function(dispatch) {
    return bindActionCreators(actionCreators, dispatch);
};

Here, actionCreators are imported from the actions.

Connecting everything

So we have the mapping functions for state and actions in place. What remains is connecting this to the presentational component. As mentioned before, the react-redux package has a function connect which does exactly that. The connect function accepts the two mapping functions (first state, second actions) and the presentational component is passed to the result. The end result is the container component we export.

In code this looks like:

const Main = connect(mapStateToProps, mapDispatchToProps)(App);

export default Main;

Wiring up

The last thing to do is replacing the App component with the Main component we just created in the root index.js file. By adding a bunch of logging statements to the code you can see that the state and the actions are passed downwards to all of the components that use them to render and set the callbacks.

Concluding remarks

For the very simple Silly App it is probably not necessary to use Redux to control the state. However, with such a simple app you can easily see how it works. From here you can extend and scale up the app. A good starting point would be to add more information to the state. If this information can be considered independent from the current state, splitting up the reducers in even smaller parts is a good idea. Another interesting point is the use of asynchronous actions. These will let you make requests to the server in a convenient way. Middlewares will come into play and make the code more interesting!


Mijn Twitter profiel Mijn Facebook profiel
Pim Hooghiemstra Webdeveloper and founder of PLint-sites. Loves to build complex webapplications using Vue and Laravel! Latest post
Deploying a vue-cli app to a subfolder

2 thoughts on “Coupling Redux to React

  1. Chris

    I’ve never done the mapDispatchToProps like that, I always do for example:

    import { addTodo, toggleTodo } from ‘./actions’;

    export default connect(mapStateToProps, { addTodo, toggleTodo })(App)

    What is the advantage of doing it that way?

    Reply
    1. Pim Hooghiemstra Post author

      Hi Chris,

      I think this becomes useful in a larger app with many actions. In such a case it becomes a bit boring to pass all those functions in an object that is passed in the connect function. I think another reason may be that when you add another action you need to manually add it to the object passed in the connect function whereas just binding all action creators at once you don’t have to worry about this.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *