Setup Redux in a React app
Tags: react, redux, javascript
Published: 2019-10-28 03:11:33

> PS - This was originally posted on my [blog](https://akhilaariyachandra.com/setup-redux-in-a-react-app/). Check it out if you want learn more about React and JavaScript!

If you have used React chances are you have run into Redux at some point or the other. [Redux](https://redux.js.org/) is a library that help in sharing one single state between many components.

Redux consists of the three parts, the **store**, **actions** and **reducer**. I'll explain each of these as we go through the post.

# Getting started

For this post I'm going to use the React app I made in an earlier [blog post](https://akhilaariyachandra.com/getting-started-in-react-with-parcel-js/) available [here](https://github.com/akhila-ariyachandra/react-parcel-starter).

```shell
git clone https://github.com/akhila-ariyachandra/react-parcel-starter.git
cd react-parcel-starter
yarn
```

First let's install all the Redux related dependencies.

```shell
yarn add redux react-redux redux-logger redux-thunk
```

- **redux** - is the main library.
- **react-redux** - makes it easier for us to use Redux in React by connecting the components to the state.
- **redux-logger** - is an optional middleware which records all changes happening in Redux in the console.
- **redux-thunk** - another optional middleware to allow asynchronous actions in Redux (more on that later).

Before we start setting up the Redux parts, let's create a folder called _redux_ in the _src_ folder to store all our Redux related code.

# Setup the Store / Initial State

The **store** is the first part of redux we are going to setup. The store is what holds the state in redux.

In the _redux_ folder create another folder called _user_ and in it create a file called _initialState.js_. This is where we'll define the initial state that redux is going to load with. We'll need one state to store the **user id**, one to store the **user** and one to indicate whether is app is in the middle of retrieving a user.

```javascript
// src/redux/user/store.js

const initialState = {
  isFetchingUser: false,
  userId: 1,
  user: {},
}

export default initialState
```

# Setup the Actions

Next we need to setup the **actions**. Actions are sort of signals used to alert redux to change the state. Actions are just javascript functions that return a object.

We'll need a couple of actions, one to change the user ID, one to change the user and another one to fetch the user from the API.

Before we create the actual actions, let's create some constants. These constants will be used to specify the type of state change that has to occur.

```javascript
// src/redux/user/constants.js

const constants = {
  IS_FETCHING_USER: "IS_FETCHING_USER",
  SET_USER_ID: "SET_USER_ID",
  SET_USER: "SET_USER",
}

export default constants
```

Now let's create the actions.

```javascript
// src/redux/user/actions.js

import constants from "./constants"

const { IS_FETCHING_USER, SET_USER, SET_USER_ID } = constants

const setIsFetchingUser = isFetching => ({
  type: IS_FETCHING_USER,
  payload: isFetching,
})

export const setUserId = userId => ({
  type: SET_USER_ID,
  payload: userId,
})

const setUser = user => ({
  type: SET_USER,
  payload: user,
})

export const getUser = userId => {
  return async dispatch => {
    dispatch(setIsFetchingUser(true))

    const response = await fetch(
      `https://jsonplaceholder.typicode.com/users/${userId}`
    )

    const responseJson = await response.json()

    dispatch(setUser(responseJson))
    dispatch(setIsFetchingUser(false))
  }
}
```

Let's go through the actions.

- **setIsFetchingUser** - This action is used to change the `isFetchingUser`.
- **setUserId** - This action is used to change the `userId`.
- **setUser** - This is used to change the `user`.
- **getUser** - Is used to get the user from the API.

**setIsFetchingUser**, **setUserId** and **setUser** are similar to each other in that they all return a JavaScript object with _type_ and _payload_. _type_ specifies the type of state change that has to occur and _payload_ contains the new value of the state.

> Note that actions to not directly change the state. They just signal to change the state.

**getUser** is different by being an asynchronous action generator. By default redux only allow for synchronous action generators, but with **redux-thunk** we can generate functions too. To create a a function generator all we need to do is return a function which has the `dispatch` argument. The `dispatch` argument is a function that is used call other redux actions inside the current function such as us calling `dispatch(setIsFetchingUser(true))` at the beginning to set `isFetchingUser` to `true`.

# Setup the Reducer

The **reducer** is the part of redux that changes the state based on the object return from the actions. The reducer has two arguments, _state_ for the state to change and _action_ for the object returned by the actions. The initial state will also be set as the default parameter of the _state_ argument.

In the reducer all that has to be done is for the state to be changed based on the action, so we check the _type_ of the action and change the state with the _payload_ of the action.

```javascript
// src/redux/user/reducer.js

import constants from "./constants"
import initialState from "./initialState"

const { IS_FETCHING_USER, SET_USER_ID, SET_USER } = constants

const reducer = (state = initialState, action) => {
  let { isFetchingUser, userId, user } = state

  switch (action.type) {
    case IS_FETCHING_USER:
      isFetchingUser = action.payload
      break
    case SET_USER_ID:
      userId = action.payload
      break
    case SET_USER:
      user = action.payload
      break
    default:
      break
  }

  return { isFetchingUser, userId, user }
}

export default reducer
```

# Setup the store

Now that we've setup the initial state, actions and reducers, it's time to tie them all together. First create _index.js_ in _src/redux_ and import the required dependencies.

```javascript
// src/redux/index.js

import thunk from "redux-thunk"
import logger from "redux-logger"
import { combineReducers, createStore, applyMiddleware } from "redux"

// Import initial states
import userState from "./user/initialState"

// Import reducers
import userReducer from "./user/reducer"
```

In order to keep our redux states organized, we will group our states. In this example, we will keep all user related data under `user`.

```javascript
const initialState = {
  user: userState,
}

const rootReducer = combineReducers({
  user: userReducer,
})
```

Then all we have to do is create the redux store and export it.

```javascript
const configureStore = () => {
  return createStore(rootReducer, initialState, applyMiddleware(thunk, logger))
}

const store = configureStore()

export default store
```

In the end _index.js_ should be like this.

```javascript
// src/redux/index.js

import thunk from "redux-thunk"
import logger from "redux-logger"
import { combineReducers, createStore, applyMiddleware } from "redux"

// Import initial states
import userState from "./user/initialState"

// Import reducers
import userReducer from "./user/reducer"

const initialState = {
  user: userState,
}

const rootReducer = combineReducers({
  user: userReducer,
})

const configureStore = () => {
  return createStore(rootReducer, initialState, applyMiddleware(thunk, logger))
}

const store = configureStore()

export default store
```

# Tying Redux to React

We could user redux as is, but we could make it easier to work with using the library **react-redux**. With react-redux we can pass the redux state and actions through props to the component.

# Building the rest of the app

To demonstrate how we can use redux to share state between multiple components we going to build the following app.

![App Preview](https://thepracticaldev.s3.amazonaws.com/i/l8d67evrbm1h3fksr6eq.png)

We can spilt the app into two components

- **Controls** - Will be used to set the userId.
- **Display** - Will be used to display the user.

# The Display component

We'll start with the Display component. Create a folder called _components_ in _src_ and then create _Display.js_ in it. Once that's done declare the component in it.

```jsx
import React from "react"

const Display = () => {
  return <div></div>
}
```

Now we can connect redux to it. We'll need the user state and the `getUser` action. We can use the `connect` import from react-redux to wrap the component with a Higher Order Component which will provide the redux state and actions. _connect_ takes two arguments.

- `mapStateToProps` - will be used to select which part of the redux state to pass into the component.
- `mapDispatchToProps` - will be used to pass the redux actions as props to the component.

For _mapStateToProps_ we need to declare a function with the redux state as the argument. It should return the state we want to send through the props.

```javascript
const mapStateToProps = state => ({
  user: state.user,
})
```

All we are doing here is accessing the user section of the redux state and sending it through the _user_ prop. The name of the key is the same as the name of the prop.

Before we declare _mapDispatchToProps_ we need two more imports.

```javascript
import { bindActionCreators } from "redux"
import { getUser } from "../redux/user/actions"
```

_getUser_ is the redux action to get the user and _bindActionCreators_ is used so that the actions can be called directly instead of inside `store.dispatch` all the time and also group them. We'll put _getUer_ inside the _actions_ prop.

```javascript
const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators({ getUser }, dispatch),
})
```

Then when exporting the component it'll be wrapped in the _connect_ Higher Order Component.

```javascript
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Display)
```

Once that's done we can access the props like this.

```jsx
import React from "react"

const Display = ({ user, actions }) => {
  return <div></div>
}
```

We can set the component to load the user every time the _userId_ in the redux state changes. If you want to learn about how to mimic react life cycle methods with hooks, check my post [here](https://akhilaariyachandra.com/mimic-react-life-cycles-methods-with-hooks/).

```javascript
React.useEffect(() => {
  actions.getUser(user.userId)
}, [user.userId])
```

After that let's complete the return of the component.

```jsx
return (
  <div>
    <table>
      <tbody>
        <tr>
          <td>ID: </td>
          <td>{user.user.id}</td>
        </tr>

        <tr>
          <td>Name: </td>
          <td>{user.user.name}</td>
        </tr>

        <tr>
          <td>Username: </td>
          <td>{user.user.username}</td>
        </tr>

        <tr>
          <td>Email: </td>
          <td>{user.user.email}</td>
        </tr>
      </tbody>
    </table>
  </div>
)
```

Finally the _Display_ component should be like this.

```jsx
// src/components/Display.js

import React from "react"
import { connect } from "react-redux"
import { bindActionCreators } from "redux"
import { getUser } from "../redux/user/actions"

const Display = ({ user, actions }) => {
  React.useEffect(() => {
    actions.getUser(user.userId)
  }, [user.userId])

  return (
    <div>
      <table>
        <tbody>
          <tr>
            <td>ID: </td>
            <td>{user.user.id}</td>
          </tr>

          <tr>
            <td>Name: </td>
            <td>{user.user.name}</td>
          </tr>

          <tr>
            <td>Username: </td>
            <td>{user.user.username}</td>
          </tr>

          <tr>
            <td>Email: </td>
            <td>{user.user.email}</td>
          </tr>
        </tbody>
      </table>
    </div>
  )
}

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

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators({ getUser }, dispatch),
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Display)
```

# The Controls component

The Controls component will only be used to change the userId in the redux user state. We don't need to fetch the user in the Controls component because the effect in the Display will automatically run whenever the userId is changed.

```javascript
React.useEffect(() => {
  actions.getUser(user.userId)
}, [user.userId])
```

This is the Controls component.

```jsx
// src/components/Controls.js

import React from "react"
import { connect } from "react-redux"
import { bindActionCreators } from "redux"
import { setUserId } from "../redux/user/actions"

const Controls = ({ user, actions }) => {
  return (
    <div>
      <button
        onClick={() => actions.setUserId(user.userId - 1)}
        disabled={user.userId <= 1 || user.isFetchingUser}
      >
        Previous
      </button>

      <button
        onClick={() => actions.setUserId(user.userId + 1)}
        disabled={user.userId >= 10 || user.isFetchingUser}
      >
        Next
      </button>
    </div>
  )
}

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

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators({ setUserId }, dispatch),
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Controls)
```

A few notes here.

- Instead of importing and using _getUser_ we're using _setUserId_
- We're limiting the _userId_ between 1 and 10 because that's the number of the user records the API has.
- We're also disabling the button based on _isFetchingUser_. It will be set to true when _getUser_ is called so the buttons will get disabled when a request to get the user is made and set to false once it's complete.

# Bringing everything together in the root component

One thing we need to do to enable _react-redux_ throughout the whole app is wrap the root component with `Provider` component from _react-redux_. Once we do that all the child components will be able to use redux through `connect`.

```jsx
// src/App.js

import React from "react"
import store from "./redux"
import Display from "./components/Display"
import Controls from "./components/Controls"
import { Provider } from "react-redux"

const App = () => {
  return (
    <Provider store={store}>
      <Display />

      <Controls />
    </Provider>
  )
}

export default App
```

_store_ is the redux store will initialize and exported in _src/redux/index.js_.

Try running the app now. The user displayed should change when the buttons are pressed even though there is no direct link between the components (i.e. passing props to each other).

# Wrap Up

This is a sample of the setup we just did. If you think you missed something, feel free to check out the code.

{% codesandbox react-redux-starter-nn8sy %}

If you found this post helpful please make sure to share it! 😊