Open In App

State Management in React – Hooks, Context API and Redux

Last Updated : 28 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

While developing a React Application, it is very important to manage the state efficiently for building fully functional applications. As React is growing there are multiple approaches introduced that can help to manage state efficiently depending upon the type of application we are building.

We will discuss the following state management techniques:

Before we dive deep into state management, let us first understand what is state in React.

What is state in React ?

React JS State is a way to store and manage the information or data while creating a React Application. The state is a JavaScript object that contains the real-time data or information on the webpage. The state in React is an instance of the React Component that can be defined as an object of a set of observable properties that control the behavior of the component. In other words, the State of a component is an object that holds some information that may change over the lifetime of the component.

Approach 1: Manage states using Hooks

Hooks were introduced in React 16.8, which makes a great revolution in functional components by helps them to manage state and lifecycle features.

useState is a fundamental hook by which we can easily able to manage states.It enables us to create and change state variables within our components, eliminating the need for class components.

Syntax:

const [state, setState] = useState(<default value>);

useReducer hook is the better alternative to the useState hook and is generally more preferred over the useState hook when you have complex state-building logic or when the next state value depends upon its previous value or when the components are needed to be optimized.

Syntax:

const [state, dispatch] = useReducer(reducer, initialArgs, init);

Example: In this example we will see how we can manage state with the help of useState Hook.

Javascript




import React, { useState } from 'react';
 
function App() {
    const [click, setClick] = useState(0);
    return (
        <div>
            <p>You've clicked {click} times!</p>
 
            <p>The number of times you have clicked
                is {click % 2 == 0 ? 'even!' : 'odd!'}</p>
 
            <button onClick={() => setClick(click => click + 1)}>
                Click me
            </button>
        </div>
    );
}
 
export default App;


Output:

Animation21

useState example output

Approach 2: Manage states using Context API

Context provides a way to pass data or state through the component tree without having to pass props down manually through each nested component. It is designed to share data that can be considered as global data for a tree of React components, such as the current authenticated user or theme(e.g. color, paddings, margins, font-sizes).

Consumer Components pass down the data but it is very difficult to write the long functional code to use this Context API. So useContext hook helps to make the code more readable, less expensive and removes the need to introduce Consumer Component. The useContext hook is the new addition in React 16.8. 

Syntax:

const authContext = useContext(initialValue);

Example: In this example we will see the basic implementation of context API.

Javascript




//auth-context.js
 
import React from "react";
 
// Creating the context object and passing the default values.
const authContext = React.createContext({ status: null, login: () => {} });
 
export default authContext;


Javascript




//App.js
 
import React, { useState } from "react";
import Auth from "./Auth";
import AuthContext from "./auth-context";
 
const App = () => {
    //using the state to dynamicallly pass the values to the context
 
    const [authstatus, setauthstatus] = useState(false);
    const login = () => {
        setauthstatus(true);
    };
    return (
        <React.Fragment>
            <AuthContext.Provider value={{ status: authstatus, login: login }}>
                <Auth />
            </AuthContext.Provider>
        </React.Fragment>
    );
};
export default App;


Javascript




//Auth.js
 
import React, { useContext } from "react";
import AuthContext from "./auth-context";
 
const Auth = () => {
    // Now all the data stored in the context can
    // be accessed with the auth variable
    const auth = useContext(AuthContext);
    console.log(auth.status);
    return (
        <div>
            <h1>Are you authenticated?</h1>
            {auth.status ? <p>Yes you are</p> : <p>Nopes</p>}
 
            <button onClick={auth.login}>Click To Login</button>
        </div>
    );
};
export default Auth;


Output:

Animation22

Context API example output

Approach 3: Manage states using Redux

Redux is a state managing library used in JavaScript apps. It simply manages the state of your application or in other words, it is used to manage the data of the application. It is used with a library like React. It makes easier to manage state and data. As the complexity of our application increases.

Building Blocks of redux:  

Example: In this example we will see the basic implementation of Redux.

Install dependency to use Redux in your application

npm install redux react-redux

Javascript




// index.js
 
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";
 
ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById("root")
);


Javascript




// App.js
 
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';
 
function App() {
    const count = useSelector(state => state.count);
    const dispatch = useDispatch();
 
    return (
        <div>
            <h1>Counter: {count}</h1>
            <button onClick={() => dispatch(increment())}>Increment</button>
            <button onClick={() => dispatch(decrement())}>Decrement</button>
        </div>
    );
}
 
export default App;


Javascript




// store.js
 
import { createStore } from 'redux';
import counterReducer from './reducers';
 
const store = createStore(counterReducer);
 
export default store;


Javascript




// reducers.js
 
const counterReducer = (state = { count: 0 }, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return {
                count: state.count + 1
            };
        case 'DECREMENT':
            return {
                count: state.count - 1
            };
        default:
            return state;
    }
};
 
export default counterReducer;


Javascript




// actions.js
 
export const increment = () => {
    return {
        type: 'INCREMENT'
    };
};
 
export const decrement = () => {
    return {
        type: 'DECREMENT'
    };
};


Output:

Animation23

Redux example output

Conclusion

By this article you have learned how to manage states using the useState and the useReducer hooks, the React Context API and the Redux Toolkit.

Its totally depend upon the type of project to choose between these options:

  • Use the useState hook for managing simple state.
  • Use useReducer when you have many states within a component or states with complex transitions.
  • Use Context API or Redux Toolkit where multiple components require or modify a shared state.


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads