Using the useContext Hook in React

The useContext hook simplifies the process of consuming context values in React, making it more concise and readable compared to using the Context.Consumer component.

Pitfall

Context Hell

Using too many nested Context Providers and Consumers can lead to "context hell," where the code becomes difficult to read and maintain due to deeply nested structures. This is similar to "callback hell" in JavaScript.

Steps to Use useContext Hook

1. Create a Context

First, we import createContext and create a new context variable outside of any function.

import React, { createContext } from 'react';
import Parent from './components/Parent';

const Name = createContext();

export { Name };

2. Provide Context

Once the context is created, we use a Provider to pass the value to subcomponents.

import React from 'react';
import { Name } from './context';

const App = () => {
    return (
        <Name.Provider value={"ReactJS"}>
            <Parent />
        </Name.Provider>
    );
}

export default App;

3. Consume Context with useContext

To consume the passed value using the useContext hook, import useContext and the context you created.

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

const Child = () => {
    const name = useContext(Name);
    
    return <h2>{name}</h2>;
}

export default Child;
Deep Dive

Using the useContext hook makes the code cleaner and easier to understand, and simplifies context consumption by eliminating the need for a Consumer component and inline function.

Example

Here's a complete example demonstrating the use of useContext to pass and consume context values.

Creating the Context

// context.js
import { createContext } from 'react';

const NameContext = createContext();

export { NameContext };

Providing Context

// App.jsx
import React from 'react';
import { NameContext } from './context';
import Parent from './components/Parent';

const App = () => {
    return (
        <NameContext.Provider value={"ReactJS"}>
            <Parent />
        </NameContext.Provider>
    );
}

export default App;

Consuming Context

// Parent.jsx
import React from 'react';
import Child from './Child';

const Parent = () => {
    return (
        <div>
            <Child />
        </div>
    );
}

export default Parent;
// Child.jsx
import React, { useContext } from 'react';
import { NameContext } from '../context';

const Child = () => {
    const name = useContext(NameContext);

    return <h2>{name}</h2>;
}

export default Child;
Task

Practice Using the useContext Hook

Objective: Create a nested component structure where data is passed down using the Context API and accessed with the useContext hook.

  1. Create a Context:

    Create a new file context.js and define a context named NameContext.

    // context.js
    import { createContext } from 'react';
    
    const NameContext = createContext();
    
    export { NameContext };
    
  2. Provide Context:

    In your main App component, use the NameContext.Provider to pass a value to subcomponents.

    // App.jsx
    import React from 'react';
    import { NameContext } from './context';
    import Parent from './components/Parent';
    
    const App = () => {
        return (
            <NameContext.Provider value={"ReactJS"}>
                <Parent />
            </NameContext.Provider>
        );
    }
    
    export default App;
    
  3. Consume Context in a Subcomponent:

    In a nested subcomponent, use the useContext hook to access the context value.

    // Child.jsx
    import React, { useContext } from 'react';
    import { NameContext } from '../context';
    
    const Child = () => {
        const name = useContext(NameContext);
    
        return <h2>{name}</h2>;
    }
    
    export default Child;
    
  4. Add Nested Structure:

    Ensure that the Parent component renders the Child component to demonstrate the context value being passed through multiple levels.

    // Parent.jsx
    import React from 'react';
    import Child from './Child';
    
    const Parent = () => {
        return (
            <div>
                <Child />
            </div>
        );
    }
    
    export default Parent;
    

This task will help you practice creating and using the Context API to manage state across deeply nested components efficiently.