Friday, 10 January 2025

React Context Beginner Guide

React Context is a feature used to share state and data globally across the entire application without needing to pass props down through every level of a component tree (known as "prop drilling"). It allows for creating a "global" variable that can be accessed by any component in the application, which is particularly useful when certain pieces of data need to be available throughout many components.

Problem That React Context Solves

React Context helps to solve the problem of prop drilling (Properties drilling). Prop drilling occurs when a parent component needs to pass data or state to deeply nested child components, requiring the intermediate components to pass the data along even if they don’t need it.

 

To explain prop drilling in a simple way, let's consider an example where we need to display an employee's name in a deeply nested component. The employee data is in the top-level component, but we need to pass it down through several levels to reach the component where it's actually used.

<App>
  <Company>
    <Department>
      <Employee />
    </Department>
  </Company>
</App>

 

The App component has the employee data, but it needs to pass this data down to the Employee component, which is deeply nested inside the Company and Department components.

 

Follow step-by-step procedure to build the complete working Application.

 

Step 1: Go to the post (Quickly Set Up a React Project with Vite: A Step-by-Step), and set up a React Project ‘props-drilling’.

 

Project structure looks like below.

 


Step 2: Create components folder in src folder and define Employee, Department and Company components.

 

Employee.jsx

export default function Employee({ employee }) {
  return (
    <>
      <h3>Employee Details</h3>
      <ul>
        <li>Name: {employee.name}</li>
        <li>Age: {employee.age}</li>
        <li>aboutMe: {employee.aboutMe}</li>
      </ul>
    </>
  );
}

Department.jsx

import Employee from "./Employee";

export default function Department({ employee }) {
  return (
    <>
      <h2>Department : {employee.department}</h2>
      <Employee employee={employee} />
    </>
  );
}

Company.jsx

import Department from "./Department";

export default function Company({ employee }) {
  return (
    <>
      <h1>Company : {employee.company}</h1>
      <Department employee={employee} />
    </>
  );
}

Step 3: Update main.jsx like below.

 

main.jsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import Company from "./components/Company";

const employee = {
  name: "Krishna",
  age: 38,
  aboutMe: "I am a Software Engineer with 13 Years Of Experience",
  department: "Research Wing",
  company: "Aerospace Research Limited",
};

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <Company employee={employee} />
  </StrictMode>
);

Step 4: Build and run the Application by executing below commands.

  cd props-drilling
  npm install
  npm run dev

Open the url ‘http://localhost:5173/’ in browser, you will see below screen.



Issues with Prop Drilling

In the example above, we had to pass the employee data through every level of the component tree, even though Company and Department didn't need to use the data themselves. This creates several problems:

 

1.   Unnecessary Complexity: Intermediate components are forced to pass props they don’t use, which can make the code harder to maintain, especially as the app grows larger.

 

2.   Scalability Issues: As the number of components or data increases, prop drilling becomes more difficult to manage. Every time you add a new piece of data, you need to modify every component in the chain.

 

3.   Tight Coupling: If the structure of the component changes, you need to update every level of the hierarchy to ensure that the data is passed correctly.

 

Solution to Prop Drilling

React Context is one solution to avoid prop drilling. With context, you can provide data from the App component directly to the Employee component without passing it through every intermediate component.

 

React Context to avoid props drilling

Let’s refactor the Employee example using React Context to solve the prop drilling issue.

 

With React Context, we can pass the employee data from the App component directly to the Employee component without passing it through intermediate components like Company and Department. This way, we avoid prop drilling.

 

How to define a React Context?

To define a context, we use React.createContext. This creates a context object, which will hold the data we want to share across components.

 

import React from 'react';

// Define a context and give it an initial value
const EmployeeContext = React.createContext(null);

 

This EmployeeContext object will be used to provide and consume the data.

 

How to provide the context data?

Once you’ve created the context, you can use the Provider component from the context to wrap the part of your component tree that needs access to the context data. The Provider component takes a value prop that is the data you want to pass down to any child components.

 

Example

const employee = {
  name: "Krishna",
  age: 38,
  aboutMe: "I am a Software Engineer with 13 Years Of Experience",
  department: "Research Wing",
  company: "Aerospace Research Limited",
};

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <EmployeeContext.Provider value={employee}>
      <Company />
    </EmployeeContext.Provider>
  </StrictMode>
);

 

How to consume the context data?

To access (consume) the context data in any child component, you can use the useContext hook or Context.Consumer.

 

Using useContext

The useContext hook allows functional components to access the context value directly.

export default function Employee() {
  const employee = useContext(EmployeeContext); // Access context data

  return (
    <>
      <h3>Employee Details</h3>
      <ul>
        <li>Name: {employee.name}</li>
        <li>Age: {employee.age}</li>
        <li>aboutMe: {employee.aboutMe}</li>
      </ul>
    </>
  );
}

 

Here, we used useContext(MyContext) to access the context data inside ChildComponent, which was provided by the App component.

 

Method 2: Using Context.Consumer (older method).

Alternatively, you can use the Context.Consumer component to access the context value. This is an older method and is often used in class-based components.

export default function Company() {
  const employee = useContext(EmployeeContext);

  return (
    <EmployeeContext.Consumer>
      {(employee) => (
        <>
          <h1>Company : {employee.company}</h1>
          <Department employee={employee} />
        </>
      )}
    </EmployeeContext.Consumer>
  );
}

 

Both methods work, but useContext is simpler and more commonly used with functional components.

 

Follow below step-by-step procedure to build the working application.

 

Step 1: Go to the post (Quickly Set Up a React Project with Vite: A Step-by-Step), and set up a React Project ‘employee-context’.

 

Project structure looks like below.

 


 

Step 2: Create utils folder in src folder and define Employee Context.

 

contexts.js

 

import React from "react";

// Define a context and give it an initial value
export const EmployeeContext = React.createContext(null);

Step 3: Create components folder in src folder, define Employee, Department, Company contexts.

 

Employee.jsx

import { EmployeeContext } from "../utils/contexts";
import { useContext } from "react";

export default function Employee() {
  const employee = useContext(EmployeeContext); // Access context data

  return (
    <>
      <h3>Employee Details</h3>
      <ul>
        <li>Name: {employee.name}</li>
        <li>Age: {employee.age}</li>
        <li>aboutMe: {employee.aboutMe}</li>
      </ul>
    </>
  );
}

Department.jsx

import { useContext } from "react";
import Employee from "./Employee";
import { EmployeeContext } from "../utils/contexts";

export default function Department() {
  const employee = useContext(EmployeeContext);
  return (
    <>
      <h2>Department : {employee.department}</h2>
      <Employee employee={employee} />
    </>
  );
}

 

Company.jsx

import { useContext } from "react";
import Department from "./Department";
import { EmployeeContext } from "../utils/contexts";

export default function Company() {
  const employee = useContext(EmployeeContext);

  return (
    <EmployeeContext.Consumer>
      {(employee) => (
        <>
          <h1>Company : {employee.company}</h1>
          <Department employee={employee} />
        </>
      )}
    </EmployeeContext.Consumer>
  );
}

 

Step 4: Update main.jsx like below.

 

main.jsx

 

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import Company from "./components/Company";
import { EmployeeContext } from "./utils/contexts";

const employee = {
  name: "Krishna",
  age: 38,
  aboutMe: "I am a Software Engineer with 13 Years Of Experience",
  department: "Research Wing",
  company: "Aerospace Research Limited",
};

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <EmployeeContext.Provider value={employee}>
      <Company />
    </EmployeeContext.Provider>
  </StrictMode>
);

 

Step 5: Build and run the application by executing below commands.

  cd employee-context
  npm install
  npm run dev

 

Open the url ‘http://localhost:5173/’ in browser, you will see below kind of screen.

 

 



 

How to Update and Delete Context Data (Without State)?

In these static examples, we are not yet using state, so there’s no mechanism to update or delete the context value. The values are provided statically through Provider and remain constant throughout the app's lifecycle.

 

To enable dynamic updates to context values, we would typically integrate useState or other state management techniques. However, without state, the values provided by context remain fixed as they are when initially rendered.

 

I will explain the integration of state with context in the next example.

 

You can download these applications from below link.

 

https://github.com/harikrishna553/frontend/tree/main/react/react-context/props-drilling

 

https://github.com/harikrishna553/frontend/tree/main/react/react-context/employee-context

 

 


Previous                                                    Next                                                    Home

No comments:

Post a Comment