Codementor Events

Step-By-Step: How to Add Redux to a React App

Published Dec 19, 2019Last updated Dec 30, 2020
Step-By-Step: How to Add Redux to a React App

Got no time? Clone the repo and get going!

git clone https://github.com/rajjeet/react-playbook
cd react-playbook/packages/react-redux
npm install
npm start

react-redux-quick-start.gif

Previous Post

Check out this post for setting up React if you're starting fresh.

In this post, we will be creating a simple counter app that increments and decrements the state. The state will be an integer.

Step 1: Import Redux NPM packages

npm install redux react-redux

Step 2: Create a Reducer

A reducer is a pure function that accepts 2 parameters: state and action. State can be anything, including objects. Action is an object with type property that specifies the type of action as a string. Let's create a countReducer in src/index.js

src/index.js
const countReducer = function (state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
};

The state is initalized as 0 (when the app starts). We handle 3 types of actions, with the default case returning the original state unchanged. The other two cases modify the value of the state and return it as a "new" state (this is important for immutability when the state is an object).

Step 2: Create a Redux Store

The store holds the state as one big global object known as a state tree. The store allows us to:
- dispatch actions to modify the state
- subscribe to recieve notification about state changes
- retrieve the entire state tree
Let's import and create the redux store and use our reducer to initialize it:

src/index.js
...
import { createStore } from 'redux';
...
let store = createStore(countReducer);
...

In our case, the entire state tree is just a single reducer. Nothing complex. We will learn how to create more complex state tree in later tutorials.

Step 3: Wrap the Main App Component with Provider

Now, we will connect redux to react using the NPM library react-redux. Let's import the <Provider />, and wrap our main app component with it. Also, pass our previously created store into the <Provider />'s store prop.

src/index.js
...
import { Provider } from 'react-redux';
...
const App = () => (
  <Provider store={store}>
    <h1>Helloworld React & Redux!</h1>
  </Provider>
);
ReactDOM.render(<App />, document.getElementById('root'));

The <Provider/> will supply our entire component tree with the global state tree.

Step 4: Create and Connect a Container Component

In the world of React & Redux, Container (smart) Components are responsible for pulling state from the Redux store, transforming it, and passing it down to Presentational (dumb) Components. Let's convert our <h1> tag into a Container Component.

src/index.js
...
import { Provider, connect } from 'react-redux';
...
const Component = () => <h1>Helloworld React & Redux!</h1>;

const Container = connect()(Component);

const App = () => (
  <Provider store={store}>
    <Container />
  </Provider>
);
...

We import the connect function from react-redux. We refactor out our original <h1> component into Component. Then, we create a new container component, called Container. The first () invokes the connect function and binds to the Redux store. Then, we invoke the returned function our Presentational Component called Component. Now, we've offically connected our Component to Redux, but it doesn't do anything special right now.

Step 5: Select and Transform State from Redux Store

Let's use our Container component to select the state and optionally, transform it.

src/index.js
...
const mapStateToProps = state => {
  return {
    count: state
  };
};
const Container = connect(mapStateToProps)(Component);
...

Here, we define a new function called mapStateToProps that literally maps or links the state from the Redux store to the component props we wish to pass to our downstream component. In this case, we convert the state (which is just a number from countReducer) to a prop called count. We should do any necessary transformations here.

Step 6: Use the State in the Presentational Component

The count prop is now being passed to our Component. Let's declare it as our parameter, and add it to the JSX. The sore responsibility of the Presentational Component is to convert props into JSX with little or no logic.

src/index.js
const Component = ({count}) => <h1>Helloworld React & Redux! {count}</h1>;

Refresh the page and you should now see 0 next to the heading. We are receiving state from Redux store now! But how do we change it? Let take a look at actions.

Step 7: Add Buttons to our Presentational Component

Now, we're going to add two buttons in our Presentational Component that increment and decrement the count.

src/index.js
const Component = ({count, handleIncrementClick, handleDecrementClick}) => (
  <div>
    <h1>Helloworld React & Redux! {count}</h1>
    <button onClick={handleDecrementClick}>Decrement</button>
    <button onClick={handleIncrementClick}>Increment</button>
  </div>
);

Notice that we are passing the two click handlers as props to the two buttons. We will provide these callbacks from the Container for dispatching actions to the Redux store. These buttons are not functional until we do this.

Step 8: Pass Callback that Dispatch Actions to Store

It's time to map our store dispatch to callback functions. Here's the change:

src/index.js
const mapDispatchToProps = dispatch => {
  return {
    handleIncrementClick: () => dispatch({ type: 'INCREMENT' }),
    handleDecrementClick: () => dispatch({type: 'DECREMENT'})
  }
};
const Container = connect(mapStateToProps, mapDispatchToProps)(Component);

We pass a second function called mapDispatchToProps to our connect function in the Container component. This function maps the dispatch function from the Redux store to the registered callbacks. These callbacks are named as the return object's property, and passed to the downstream component as props (handleIncrementClick and handleDecrementClick). Now, it should work! We can modify the state using the buttons!

Step 9 (optional): Refactor the Code

Let's move the similar code into separate files to keep the project tidy and maintained. Let's create a separate file for the the Container component, Presentational component, store initialization, and reducer. Also, let's put all the counter code into a single directory, because as the project grows, we will create other components with their own reducers, containers, and presentational components. The final directory structure should look like this:

src
├── configure-store.js
├── counter
│   ├── component.js
│   ├── container.js
│   └── reducer.js
├── index.html
└── index.js

And here's the code in each file:

src/counter/component.js
import React from 'react';

export const Component = ({ count, handleIncrementClick, handleDecrementClick }) => (
  <div>
    <h1>Helloworld React & Redux! {count}</h1>
    <button onClick={handleDecrementClick}>Decrement</button>
    <button onClick={handleIncrementClick}>Increment</button>
  </div>
);
src/counter/container.js
import { connect } from 'react-redux';
import { Component } from './component';

const mapStateToPros = state => {
  return {
    count: state
  };
};
const mapDispatchToProps = dispatch => {
  return {
    handleIncrementClick: () => dispatch({ type: 'INCREMENT' }),
    handleDecrementClick: () => dispatch({ type: 'DECREMENT' })
  }
};
export const Container = connect(mapStateToProps, mapDispatchToProps)(Component);
src/counter/reducer.js
export const countReducer = function (state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
};
src/configure-store.js
import { createStore } from 'redux';
import { countReducer } from './counter/reducer';

export const store = createStore(countReducer);
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './configure-store';
import { Container } from './counter/container';

const App = () => (
  <Provider store={store}>
    <Container />
  </Provider>
);

ReactDOM.render(<App />, document.getElementById('root'));

Conclusion

Thanks for reading. Checkout the code at my Github. If you have suggestions or want to discuss, leave a comment here!

Discover and read more posts from Rajjeet Phull
get started
post comments10Replies
Guddu Kumar
2 years ago

Thank you rajjeet Phul for explaining redux. this article helped me for using add redux in react-project

deventj
3 years ago

Thank you, by far the best reading so far to better understand react-redux!

Jilvan Candido
4 years ago

Simple and straight to the point. Nice article!

Show more replies