Using Context API in React

Props are great for passing data down to one or two subcomponents, but when dealing with deeply nested components, props can become cumbersome and increase the complexity of the code. The Context API provides a way to share values between components without explicitly passing props through every level of the component tree.

The Context API in React provides a way to pass data through the component tree without having to pass props down manually at every level. This is especially useful for managing global state in a React application.

Steps to Use Context API

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;

Now, the value is ready to be accessed by any subcomponent within Parent.

3. Consume Context

To consume the passed value, subcomponents use the Consumer component.

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

const Child = () => {
    return (
        <Name.Consumer>
            {(value) => {
                return <h2>{value}</h2>;
            }}
        </Name.Consumer>
    );
}

export default Child;
Info

For a more concise way to consume context values, see useContext.

Example

Here's a complete example demonstrating the use of Context API 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 from 'react';
import { NameContext } from '../context';

const Child = () => {
    return (
        <NameContext.Consumer>
            {(value) => {
                return <h2>{value}</h2>;
            }}
        </NameContext.Consumer>
    );
}

export default Child;
Task

Practice Using the Context API

Objective: Create a nested component structure where data is passed down using the Context API with multiple Providers and Consumers.

  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 Context.Consumer component to access the context value.

    // Child.jsx
    import React from 'react';
    import { NameContext } from '../context';
    
    const Child = () => {
        return (
            <NameContext.Consumer>
                {(value) => {
                    return <h2>{value}</h2>;
                }}
            </NameContext.Consumer>
        );
    }
    
    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;
    
  5. Use Multiple Providers and Consumers:

    Modify the structure to include multiple contexts, providers, and consumers to understand handling multiple global states.

    // context.js
    import { createContext } from 'react';
    
    const NameContext = createContext();
    const AgeContext = createContext();
    
    export { NameContext, AgeContext };
    
    // App.jsx
    import React from 'react';
    import { NameContext, AgeContext } from './context';
    import Parent from './components/Parent';
    
    const App = () => {
        return (
            <NameContext.Provider value={"ReactJS"}>
                <AgeContext.Provider value={25}>
                    <Parent />
                </AgeContext.Provider>
            </NameContext.Provider>
        );
    }
    
    export default App;
    
    // Child.jsx
    import React from 'react';
    import { NameContext, AgeContext } from '../context';
    
    const Child = () => {
        return (
            <NameContext.Consumer>
                {(name) => (
                    <AgeContext.Consumer>
                        {(age) => {
                            return (
                                <div>
                                    <h2>{name}</h2>
                                    <h3>{age}</h3>
                                </div>
                            );
                        }}
                    </AgeContext.Consumer>
                )}
            </NameContext.Consumer>
        );
    }
    
    export default Child;
    

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