State Management in React with Context

Brendah KiraguBrendah Kiragu
4 min read

React Context and the useContext

As I embarked on learning React, I was first introduced to props. Props offer a straightforward way to pass data from parent to child components. This method worked well when passing data from a parent to an intermediate child. However, as I began building applications with more complex component hierarchies, the limitations of prop drilling became apparent.

For instance, consider a scenario where you have:

  • Parent

    • Child A

      • Child B

        • Child C

          • Child D

Passing data from Parent to Child D requires prop drilling through each level, making the code complex and hard to maintain. While prop drilling works for simpler applications, it becomes cumbersome in larger, more deeply nested component structures.

Fortunately, React offers a more efficient solution: the Context API and the useContext hook. These tools eliminate the need for prop drilling and simplify state management across components. This article will explore using the Context API to manage State effectively.

Key Concepts

Before we dive into the code, let’s clarify some key concepts:

  • Context: A mechanism for sharing values between components without manually passing props through every level of the component tree. It provides a way to manage the global state in your component hierarchy.

  • Provider: A component that holds the state and provides it to its descendants. It wraps around components that need access to the context.

  • Consumer: A component that consumes the context values provided by the Provider. With modern React, the useContext hook is used to access context values without explicitly using the Consumer component.

In our example, we will create a context that holds a string value and a function to update that value, demonstrating how to share state across components seamlessly.

Code Structure

The code is organized into three main components:

  1. MyProvider: Creates the context and holds the state.

  2. ChildComponent: Consumes the context and displays the value, with a button to change it.

  3. App: Wraps the ChildComponent with MyProvider.

Code Examples

Here is the complete code for our example:

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

// Create a Context
const MyContext = createContext();

const MyProvider = ({ children }) => {
  const [value, setValue] = useState("Hello, World!");

  return (
    <MyContext.Provider value={{ value, setValue }}>
      {children}
    </MyContext.Provider>
  );
};

const ChildComponent = () => {
  const { value, setValue } = useContext(MyContext);

  return (
    <div>
      <h1>{value}</h1>
      <button onClick={() => setValue("Hello, Welcome to React!")}>Change Text</button>
    </div>
  );
};

const App = () => {
  return (
    <MyProvider>
      <ChildComponent />
    </MyProvider>
  );
};

export default App;

Explanation of the Code

Step 1: Creating the Context

const MyContext = createContext();

Here, we create a context using createContext(). This function returns a context object with two components: Provider and Consumer. This context object allows us to share data across components.

Step 2: Setting up the Provider Component

const MyProvider = ({ children }) => {
  const [value, setValue] = useState("Hello, World!");
  return (
    <MyContext.Provider value={{ value, setValue }}>
      {children}
    </MyContext.Provider>
  );
};

The MyProvider component initializes a state variable value with the default string "Hello, World!". It also provides a function setValue to update this state. The MyContext.Provider wraps its children, making value and setValue accessible to any component that consumes this context.

Step 3: Using the useContext Hook to Pass Data to Child Component

const ChildComponent = () => {
  const { value, setValue } = useContext(MyContext);
  return (
    <div>
      <h1>{value}</h1>
      <button onClick={() => setValue("Hello, Welcome to React!")}>Change Text</button>
    </div>
  );
};

In ChildComponent, we use the useContext hook to access the context values. The component displays the current value and includes a button that, when clicked, updates the value to "Hello, React!".

Step 4: Providing Context to Child Component via Main App Component

const App = () => {
  return (
    <MyProvider>
      <ChildComponent />
    </MyProvider>
  );
};

The App component serves as the entry point of our application. It wraps ChildComponent with MyProvider, ensuring that the context is available to it.

Real-World Use Case

While this example demonstrates a basic usage of the Context API, it is also highly effective for managing more complex states, such as user authentication, theming, or global settings. For instance, you might use the Context API to manage a user’s authentication status across an entire application or to toggle between light and dark modes.

Conclusion

The React Context API simplifies state management across complex component hierarchies by eliminating the hassle of prop drilling. By leveraging context, we can share data and functions between components without having to pass props through every level of the component tree.

This approach not only simplifies state management but also enhances code readability and maintainability.

documentation reference: https://react.dev/reference/react/useContext

Let's connect on LinkedIn www.linkedin.com/in/brendah-mwihaki-kiragu-10432218a

0
Subscribe to my newsletter

Read articles from Brendah Kiragu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Brendah Kiragu
Brendah Kiragu