State management in React using Redux and React-redux

State management in React using Redux and React-redux

In this post we will give you information about State management in React using Redux and React-redux. Hear we will give you detail about State management in React using Redux and React-reduxAnd how to use it also give you demo for it if it is necessary.

we are going to learn about how to manage the state in react by using redux and react-redux libraries.

If you want to learn basics about redux then check out previous tutorial React Redux beginnerstutorial.

Getting started

First, we need to install the new react app by using a create-react-app command line tool.

Run the below command to install the react app.

npx create-react-app redux-tutorial

This above command will download the react related files in the “redux-tutorial” folder.

Once you successfully installed now change your working directory to app directory by using belowcommands.

cd redux-tutorialnpm start

npm start command is used turn on the local development server on localhost:3000.

Note: If you stuck anywhere in this tutorial then please checkout code repository on [GitHub](

https://github.com/saigowthamr/redux-tutorial)

Installing Redux Library

Let’s install the redux and react-redux library by using following commands.

npm i redux react-redux

redux : Redux is used to manage the state

react-redux : It is used to make the bindings between the redux library and react.

Now open your “redux-tutorial” folder by using your favorite codeeditor.

Reducer function

Reducer function is a pure function which takes the previous app state, type of action andreturns the next state without mutating the previous state.

Redux follows the immutability it means we are not mutating the app state instead of we are returning thenew app state.

Redux manages the whole app state in the single JavaScript object.

create a new folder called reducers in your src directory.

Inside the reducers, folder create a new file called reducer.js.

reducer.js
<span>const intialState = { name: "onlinecode", allNames: []}const reducer = (state <span>= intialState, action) =&gt; {    if (action.type === "ADDNAME") {        return {            allNames: state.allNames.concat(state.name),            name: ""        }    }    if (action.type === "CHANGE_NAME") {        return {            ...state,            name: action.name        }    }    return state}export default reducer;

In the above code, we have defined a reducer function with two parameters state and action.Inside the reducer function, we have added two conditional statements.

Our initial state object is { name: “”, allNames: []}.

Connecting React with Redux

Its time to connect our react app with the redux.

Open your index.js present inside your src folder.

index.js
import React from 'react';import ReactDOM from 'react-dom';import { createStore } from 'redux'import { Provider } from 'react-redux';import App from './App';import reducer from './reducers/reducer'const store = createStore(reducer);ReactDOM.render(    &lt;Provider store={store}&gt;        &lt;App /&gt;    &lt;/Provider&gt;    , document.getElementById('root'));

Inside the index.js file we imported createStore function from the ‘redux’ library andProvider component from the react-redux library.

We invoke the createStore function by passing the reducer function as an argument and we wrap the<Provider> component with the <App/> component by passing a store attribute.

<Provider> component uses the react context API to pass the state down through the component tree.

Accessing the redux state from the components

Now we can access our redux state straight from the React components.

Open your App.js file and add the below code.

mapStatetoProps example

import React, { Component } from 'react';import { connect } from 'react-redux'import './App.css'class App extends Component {  render() {    return (      &lt;div className="App"&gt;        &lt;div&gt;          &lt;input type="text"            placeholder="Name"            value={this.props.name} /&gt;      &lt;/div&gt;    );  }}const mapStatetoProps = (state) =&gt; {  return {    name: state.name,  }}export default connect(mapStatetoProps)(App);

Here we first imported the Higher-order component called connect from the react-redux librarythen we defined a mapStatetoProps function with the state parameter.

By using state parameter we can access the redux state which we defined inside the reducer function.

Any property we defined inside the mapStatetoProps function can available as a props inside the App component for example ,In the above component we returned an object with {name:state.name} so that we can access that name property inside the App component as a this.props.name.

At last, we need to invoke the connect function by passing the mapStatetoProps as an argument.

If you open your browser now you can see “onlinecode” is displayed inside the input field.

Mutating the Redux state

The redux state tree is read-only, we can’t mutate the state directly.

In redux, we can only mutate the state by invoking a dispatch method with the type of action.

If you open reducer.js file you can see they are two types of actions available which are ADDNAME and CHANGE_NAME.

reducer.js
const intialState = { name: "onlinecode", allNames: []}const reducer = (state <span>= intialState, action) =&gt; {    if (action.type === "ADDNAME") {        return {            allNames: state.allNames.concat(state.name),            name: ""        }    }    <span>if (action.type === "CHANGE_NAME") {        return {            ...state,            name: action.name        }    }    return state}export default reducer;

If we invoke the dispatch method with the type ADDNAME then we are returning the new state with thename property values are added to the allNames array and resetting the name property.

Let’s see in action.

Open your App.js file add the below code.

mapDispatchtoProps example

App.js
import React, { Component } from 'react';import { connect } from 'react-redux'import './App.css'class App extends Component {  handleNameChange = (e) =&gt; {    this.props.onChangeName(e.target.value)  }  render() {    return (      &lt;div className="App"&gt;        &lt;div&gt;          &lt;input type="text"            placeholder="Name"            value={this.props.name} onChange={this.handleNameChange} /&gt;          &lt;button onClick={this.props.onAddName}&gt;Add name&lt;/button&gt;          &lt;ul&gt;            {this.props.allNames &amp;&amp; this.props.allNames.map(name =&gt; (              &lt;li key={name}&gt; {name}&lt;/li&gt;            ))}          &lt;/ul&gt;&lt;/div&gt;      &lt;/div&gt;    );  }}const mapStatetoProps = (state) =&gt; {  return {    name: state.name,    allNames: state.allNames  }}const mapDispatchtoProps = (dispatch) =&gt; {  return {    onChangeName: (name) =&gt; dispatch({ type: "CHANGE_NAME", name: name }),    onAddName: () =&gt; dispatch({ type: "ADDNAME" }),  }}export default connect(mapStatetoProps, mapDispatchtoProps)(App);

In the above, we defined a mapDispatchtoProps function where we get the dispatch method as a function parameter.

Inside the mapDispatchtoProps function we returned a object with two properties onChangeName andonAddName

onChangeName : it helps us to dispatch the action type CHANGE_NAME and payload name property which is added by the user.

onAddName: it helps us to dispatch the action type ADDNAME.

We can access these two properties inside the App component as a props.

Let’s test it now in the browser.

Handling the Errors

We can also handle the errors by creating an ERROR type inside the reducer function.

Update your reducer.js file with below code

reducer.js
const intialState = { name: "onlinecode", allNames: [], error: "" }const reducer = (state <span>= intialState, action) =&gt; {    if (action.type === "ADDNAME") {        return {            allNames: state.allNames.concat(state.name),            name: ""        }    }    <span>if (action.type === "CHANGE_NAME") {        return {            <span>...state,            name: action.name        }    }    if (action.type === "ERROR") {        return {            ...state,            error: action.error        }    }    return state}export default reducer;

In the above code, we updated our reducer function by adding aa third conditional statement with type ERROR and error property is added to ourinitialState object.

Let’s dispatch the action type ERROR in our App component.

App.js
import React, { Component } from 'react';import { connect } from 'react-redux'import './App.css'class App extends Component {  handleNameChange = (e) =&gt; {    this.props.onChangeName(e.target.value)  }  handleClick = () =&gt; {    if (this.props.name) {      this.props.onAddName()    } else {      <span>this.props.onError("Name field cannot be empty")    }  }  render() {    return (      &lt;div className="App"&gt;        &lt;div&gt;          &lt;input type="text"            placeholder="Name"            value={this.props.name} onChange={this.handleNameChange} /&gt;          &lt;button onClick={this.handleClick}&gt;Add name&lt;/button&gt;          &lt;p className={this.props.error ? "error active" : "error"}&gt;          {this.props.error}&lt;/p&gt;          &lt;ul&gt;            {this.props.allNames &amp;&amp; this.props.allNames.map(name =&gt; (              &lt;li key={name}&gt; {name}&lt;/li&gt;            ))}          &lt;/ul&gt;&lt;/div&gt;      &lt;/div&gt;    );  }}const mapStatetoProps = (state) =&gt; {  return {    name: state.name,    error: state.error,    allNames: state.allNames  }}const mapDispatchtoProps = (dispatch) =&gt; {  return {    onChangeName: (name) =&gt; dispatch({ type: "CHANGE_NAME", name: name }),    onAddName: () =&gt; dispatch({ type: "ADDNAME" }),    onError: (err) =&gt; dispatch({ type: "ERROR", error: err })  }}export default connect(mapStatetoProps, mapDispatchtoProps)(App);

In the above, we added a conditional check inside the handleClick method so thatwhenever a user tries to click on a Add name button without typing the name, we are invoking the this.props.onError method by passing an error message.

output

Refactoring the code

It’s hard to type the action types in many places manually so that we are acreating two new files which are actionCreators.js and actionTypes.js

In actionTypes.js file we are defining all our actions types.

Currently, we have three types of actions in our app CHANGE_NAME , ADDNAME and ERROR

Create a actions folder in your src directory.

Inside the actions folder create an actionTypes.js file and the below code.

actionTypes.js
export const ADDNAME = "ADDNAME";export const CHANGE_NAME = "CHANGE_NAME";export const ERROR = "ERROR";

create a new file called actionCreators.js inside your actions folder.

actionCreators.js
import { CHANGE_NAME, ADDNAME, ERROR } from './actionTypes'export function changeName(name) {    return {        type: CHANGE_NAME,        name: name    }}export function addname() {    return {        type: ADDNAME    }}export function error(msg) {    return {        type: ERROR,        error: msg    }}

In the above, we have created three action creators which returning the three differenttype of actions.

Action creators are JavaScript functions which return the objects with a type of actions.

Update your reducer.js file with actionTypes

reducer.js
import { CHANGE_NAME, ADDNAME, ERROR } from '../actions/actionTypes'const intialState = { name: "onlinecode", allNames: [], error: "" }const reducer = (state = intialState, action) =&gt; {    if (action.type === ADDNAME) {        return {            allNames: state.allNames.concat(state.name),            name: ""        }    }    if (action.type === CHANGE_NAME) {        return {            ...state,            name: action.name        }    }    if (action.type === ERROR) {        return {            ...state,            error: action.error        }    }    return state}export default reducer;

Update the App.js file with the action creators.

App.js
import React, { Component } from 'react';import { connect } from 'react-redux'import { addname, error, changeName } from './actions/actionCreators'import './App.css'class App extends Component {  handleNameChange = (e) =&gt; {    this.props.onChangeName(e.target.value)  }  handleClick = () =&gt; {    if (this.props.name) {      this.props.onAddName()    } else {      this.props.onError("Name field cannot be empty")    }  }  render() {    return (      &lt;div className="App"&gt;        &lt;div&gt;          &lt;input type="text"            placeholder="Name"            value={this.props.name} onChange={this.handleNameChange} /&gt;          &lt;button onClick={this.handleClick}&gt;Add name&lt;/button&gt;          &lt;p className={this.props.error ? "error active" : "error"}&gt;          {this.props.error}&lt;/p&gt;          &lt;ul&gt;            {this.props.allNames &amp;&amp; this.props.allNames.map(name =&gt; (              &lt;li key={name}&gt; {name}&lt;/li&gt;            ))}          &lt;/ul&gt;&lt;/div&gt;      &lt;/div&gt;    );  }}const mapStatetoProps = (state) =&gt; {  return {    name: state.name,    error: state.error,    allNames: state.allNames  }}const mapDispatchtoProps = (dispatch) =&gt; {  return {    onChangeName: (name) =&gt; dispatch(changeName(name)),    onAddName: () =&gt; dispatch(addname()),    onError: (err) =&gt; dispatch(error(err))  }}export default connect(mapStatetoProps, mapDispatchtoProps)(App);

Have you seen now our code looks a bit organized?.


Code repository

Hope this code and post will helped you for implement State management in React using Redux and React-redux. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs

For More Info See :: laravel And github

We're accepting well-written guest posts and this is a great opportunity to collaborate : Contact US