React-Redux

Issa Sangare
Level Up Coding
Published in
8 min readDec 1, 2020

--

If you want to avoid Prop Drilling which is to pass props from React parent component to its children or grand children component, you do want to read this tutorial about React-Redux.

What is Redux?

According to Redux documentation, Redux is a pattern and library for managing and updating application state, using events called “actions”. It serves as a centralized store for state that needs to be used across your entire application, with rules ensuring that the state can only be updated in a predictable fashion.

In this tutorial, we’re going to set up our file structure like below with a folder for reducers which we will talk about later on.

First things first, we need to install react-redux and redux’s library:

npm install redux and npm install react-redux and then let’s start our journey with index.js file.

index.js file:

Here, we have imported Provider Component from react-redux. What’s Provider? This is a context wrapper which we are going to use to wrap up our entire application and which receives the store as a property. Its sole purpose is to make Redux store available to the rest of our App via Redux’s methods.

Now, let’s talk about Redux store. The Redux store brings together the state, actions, and reducers that make up your app. Store is like an external state container where every React components can get access to it. Very important and to recall, you’ll only have a single store in a Redux application.

Create a store

In line 7, we have imported createStore from redux. CreateStore is a function that creates a Redux store and will take as an argument reducer function. In this time around, we have passed in rootReducer. What’s rootReducer? it’s also a reducer function but for now, let’s put that question on hold and we will get back to it shortly. In line 10, we used createStore function to create our Redux store and assigned it to the variable store. In line 13, we passed our store as props or property to the Provider Component, thus that Redux store would be accessible to every single component of our whole App via some Redux functions.

Reducers folder:

In this folder, there are two files: imageReducer.js and rootReducer.js.

What’s reducer: Reducer is a redux function that will be passed into createStore as the argument. To recall, you could have numerous reducers but you can pass into createStoreonly a single reducer function. We’ll cover this later on in this blog.

  1. imageReducer.js: In this file in line 1, we have just set an initialState because every reducer needs some initial state. In line 5, we have passed into our ImgReducer function as arguments the initialState and the action. So far, ImgReducer is the only reducer function for our App. To remember, reducers normally use ES6 default argument syntax to provide the initial state: (state = initialState, action).

2. rootReducer.js: In this file rootReducer.js, the first thing we have done was to import ImgReducer from “./imageReducer”. In here, we have another Reducer function which is reducer. As stated above, we can only pass one reducer as an argument into createStore function, since we have two reducers we will need another function that can combine our two reducers into one. For this reason, we have to import combineReducers function from redux. The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.

In line 26, we have passed our two reducers ImgReducer & reducer into combineReducers and assigned it to the variable rootReducer and finally, we made that rootReducer exportable.

Back to index.js file:

In line 8, we have imported rootReducer inside index.js file. In line 10, we have passed rootReducer as an argument into createStore function and assigned it to our Redux store. At this point, our Redux store encompasses our state, actions, and rootReducer (combineReducers). And finally, we have passed that store as property to the Provider Component in order to make it reachable, throughout the whole application, to all components.

Count.js file:

How components get access to Redux store’s data?

React-redux provides us another function connect() which components can use to get access to store’s data. The connect() function connects a React component to a Redux store. It has two purposes: it will connect the component to store so that it gets data from the store and dispatch information to store. Let’s consider connect as a connector or bridge between React component and Redux store.

Now let’s find out how we can connect our functional component Counter to our Redux store and get can data from it. First things first, we need to import connect from 'react-redux' (line2).

Connect accepts four different parameters, all optional. By convention, they are called:

  1. mapStateToProps?: Function
  2. mapDispatchToProps?: Function | Object
  3. mergeProps?: Function
  4. options?: Object

In this example, we are going to use the first two: mapStateToProps and mapDispatchToProps.

mapStateToProps

It is a function and by convention, it will be the first parameter of the connect function. Your mapStateToProps functions are expected to return an object. This object, normally referred to as stateProps, will be merged as props to our connected component which is here Counter component.

Since we are using connect() to connect our Counter component to store, let’s name the parameter we have passed to mapStateToProps as store and console.log it (you can give whatever name you would like).

It turned out that our store encompasses our rootReducer (ImgReducer and reducer) where our state is located. Since mapStateToProps is expected to return state our goal here is to get access to state from rootReducer and return it.

Accessing to State from our reducers:

Returning State: For this component we only need count field for our Counter component and we know count is inside reducer that will be easy to retrieve. As we know mapStateToProps will return an object therefore let’s name the key of this object count and its value will be store.reducer.count.

As stated above, whatever mapStateToProps return will be a props for our Counter component. Let’s check it out inside the developer tools if there is any props. As you can see below our Counter component has now count as props.

mapDispatchToProps

Conventionally, the second parameter connect() takes is mapDispatchToProps. To recall, your component will receive dispatch by default for instance you do not provide a second parameter to connect().

If your mapDispatchToProps is declared as a function taking one parameter, it will be given the dispatch of your store. Your mapDispatchToProps functions are expected to return an object, each field of the object should be a function, calling which is expected to dispatch an action to the store. Whatever it returns will be merged as props to your connected component which here Counter component.

Dispatch: it takes as argument action. Actions are plain JavaScript objects that have a type field. You can think of an action as an event that describes something that happened in the application. On top of that, actions have also payload field and we put any extra data needed to describe what’s happening into the action.payload field. This could be a number, a string, or an object with multiple fields inside.

Since the return of mapStateToProps and mapDispatchToProps functions will be merged as props to your connected Counter component, let’s open up our DevTools and check it out. We can see below that our component has some props: count, decrement and increment.

Let’s console.log inside our connected Counter component those props we have received from mapStateToProps and mapDispatchToProps by using connect function.

rootReducer.js:

Let me walk you through our reducer function. It takes two arguments state and action. We used Switch case statement to check the condition, if action.type is “inc” we want our reducer function to return the current state first and then update count field by increasing it. In this example, we have used spread operator to make a copy of our current (…state).On the other hand, if action.type is “dec”, we want our reducer to return the current state and update count field by decreasing it. If none of those conditions are not met our reducer function will return by default the current state.

At this point, though, I hope you can see how Redux makes our life more easier by avoiding the so-called Prop Drilling which is to pass data from one part of the React Component tree to another by going through other parts that do not need the data but only help in passing it around

If you made it this far, thanks for reading!

PS: I shared below the ImgComponent and it’s not going to be commented it since we have already covered the same process inside counter.js file throughcounter Component.

resources: https://redux.js.org/introduction/getting-started,

https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers,

https://react-redux.js.org/7.1/api/connect#connect,

https://react-redux.js.org/7.1/introduction/why-use-react-redux

--

--