Simplifying State Management with React’s useContext Hook

Simplifying State Management with React’s useContext Hook

React is a popular JavaScript library for building user interfaces, and one of its core principles is the concept of state management. State allows components to keep track of data and update the UI accordingly. In this blog post, we will explore the powerful useContext hook, which simplifies state management in React and provides a delightful developer experience.This blog targetting the audience who just wants to learn about useContext hook for their project or those who want to refresh their concepts

Understanding The Problem Of Prop Drilling

React's useContext hook addresses the problem of prop drilling, which occurs when we need to pass data down multiple levels in the component tree. Prop drilling can make the codebase hard to maintain and lead to performance issues. The useContext hook simplifies this process by allowing us to share state or other values across components without the need for intermediate component props.

Example: Imagine a music player application with components like App, Player, Playlist, and Song. The App component holds the state for the currently playing song, and we need to pass this state down to the Song component for display. Without useContext, we would have to pass the currently playing song as props from App to Player, then from Player to Playlist, and finally from Playlist to Song. This creates a tangled web of props and makes the code difficult to maintain.

Prop Drilling in React - Scaler Topics

Lifting State Up Understanding the Jargon Before diving into the useContext hook, it's important to grasp the concept of "lifting state up." In React, "lifting state up" refers to the practice of moving the state from a lower-level component to a higher-level component, making it accessible to multiple child components. By lifting state up, we centralize the management of that state, simplifying the data flow and reducing the complexity of passing props between components.

If you are not too familiar with "lifting state up in react" then I will strongly recommend you to learn the basics at least first(it will hardly take 15-20 minutes) and then continue learning useContext hook.

🎉Introducing useContext for Elegant State Management

Let's explore the steps and best practices for using the useContext hook effectively in functional components:

Step 1: Import the necessary modules

Start by importing React and the `useContext` hook from the React library.

import React, { useContext } from 'react';

Step 2: Creating a Context

To get started, we need to create a context using the createContextfunction provided by React. This function returns a context object that consists of two components: Provider and Consumer. We will focus on the Provider component for now.

const MyContext = React.createContext();
// you can use any name for creating context in place of MyContext

STEP 3: Create a Context Provider

import React, { createContext,useState } from 'react';

const MyContext = createContext();

const MyContextProvider = ({ children }) => {
  // Define the shared state and functions here and pass them in the value{}

// lets take an example of counter

 const [count, setCount] = useState(0); // Shared state

 const incrementCount = () => {
    setCount(count + 1);
  };

  const decrementCount = () => {
    setCount(count - 1);
  };

  return <MyContext.Provider value={{ count,setCount, incrementCount, decrementCount}}>
{children}
</MyContext.Provider>;
};

export {MyContext, MyContextProvider}

Step 4: Wrap the Components with the Provider

💡This is a very crucial step where beginners tend to do mistake

import React from 'react';
// importing  context provider
import { MyContextProvider } from './MyContext';
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';

const App = () => {
  return (
    <MyContextProvider>
      <ComponentA />
      <ComponentB />
    </MyContextProvider>
  );
};

export default App;

Step:5 Access the Context in the Consuming Components

In the components where you want to access the context value, use the useContext hook to consume the context.

import React, { useContext } from 'react';
// importing context 
import { MyContext } from './MyContext';

const ComponentA = () => {
//👉passing MyContext in useContext hook as argument

  const { count, incrementCount } = useContext(MyContext); // Access the shared state and functions

  return (
    <div>
      <h2>Component A</h2>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
};

export default ComponentA;

This is all you need to know about useContext hook in react. I would recommend you learn about the refactoring techniques I discussed below.


⭐Refactoring useContext in React: Consuming Context within the MyContext File.

Imagine you have many components in which you need to consume value from context. For that you have to import context every time which can be a little messy and frustrating so to overcome that situation you can refactor the useContext hook by consuming the context in the MyContext file itself, eliminating the need to import it in every single component:

Let me show you example by refactoring the above code :

  1. The first change you need to make is importing useContext in context file it self
import React, { createContext, useState, useContext } from 'react';
  1. Define a custom hook, let's call it UseMyContext, which consumes the context and returns the shared state and functions:

    ```javascript import React, { createContext,useState } from 'react';

    const MyContext = createContext();

    export const MyContextProvider = ({ children }) => { // Define the shared state and functions here and pass them in the value{}

    // lets take an example of counter

    const [count, setCount] = useState(0); // Shared state

    const incrementCount = () => { setCount(count + 1); };

    const decrementCount = () => { setCount(count - 1); };

    return {children} ; };

export function UseMyContext (){ return useContext(MyContext) }



Consuming the Context in Components:

```javascript
import React from 'react';
//  👉 importing UseMyContext and no need to import useContext from react 
import { UseMyContext } from './MyContext';

const ComponentA = () => {
// 👉 Access the shared state and functions using custom hook in context hook 
  const { count, incrementCount } = useMyContext(); 

  return (
    <div>
      <h2>Component A</h2>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
};

export default ComponentA;

Conclusion 👋

The useContext hook is a powerful tool for simplifying state management and context consumption in React applications. By following the steps outlined in this article, you can effectively create and consume context, access shared state and functions, and streamline your React codebase. Leveraging the useContext hook empowers you to build scalable, maintainable, and efficient applications. Start harnessing the power of useContext today, and unlock the full potential of React's Context API.

Happy coding!🎉