November 25, 2022

React useContext Hook With Examples

In React application, props is one way to pass data from parent to child component. But it may become an overhead to maintain props in each component if you have a big hierarchy of nested components. React Context API provides another way to maintain global state. Once a context is created with some value in a component, that context will be available to all the nested child components without using "props". The useContext hook in React is used to read the context value in a component where it is needed.

Why useContext hook in React

First let's try to understand what exactly is the problem with props where useContext hook provides a better alternative than "props-drilling".

As an example, we have 3 components ComponentA, ComponentB and ComponentC and we have to pass data from parent component (ComponentA) to child component.

ComponentA.js

From ComponentA, value for theme is passed to the child component, ComponentB.

import ComponentB from "./ComponentB";
const ComponentA = () => {
    return(
        <ComponentB theme="dark"></ComponentB>
    );
}    
export default ComponentA;

ComponentB.js

The same theme value has to be passed to the ComponentC so you'll again use props to pass it further down.

import ComponentC from "./ComponentC";
const ComponentB = (props) => {
    return(
     <ComponentC theme={props.theme}></ComponentC>
    );
}    
export default ComponentB;

ComponentC.js

const ComponentC = (props) => {
    return (
        <p>Current theme is- {props.theme}</p>
    );
}    
export default ComponentC;

Though a simple example with not much nesting but the problem here, as you can notice, is that ComponentB has to do the task of passing the props further down to make it available to ComponentC. You don't have any mechanism to pass that data directly from ComponentA to ComponentC so that all the components in the hierarchy don't have to manage props.

Context provides you with that mechanism to provide data to the nested components without the overhead of managing props.

How to work with useContext

In order to understand how useContext works you'll have to understand the working of React Context API which has three main steps.

  1. Create context using React.createContext.
  2. Enclose the component with <CreatedContext.Provider>. Using Provider lets you provide a context value.
    <CreatedContext.Provider value="ctxValue">
        <SomeComponent />
    </CreatedContext.Provider>
    

    React Context guarantees that this SomeComponent component and any components inside it, no matter how deep, will be able to access the passed context values.

    If the passed context values change, React will re-render the components reading the context as well.

  3. Read the context value in the Component where you need it using useContext() hook.

useContext hook syntax

const value = useContext(SomeContext)

parameters

SomeContext: The argument passed to the useContext() is the context that you've previously created with createContext.

useContext returns the context value for the calling component.

useContext React example

If we take the same example of 3 components ComponentA, ComponentB and ComponentC where we have to pass some data from parent component (ComponentA) to child component. This time we'll use Context to pass data.

1. Creating Context

First step is to create Context. Since many components in different files will need access to the same context so it's common to declare contexts in a separate file.

Contexts.js

import { createContext } from 'react';
export const ThemeContext = createContext('light');

You can pass default value while creating context. If matching context provider is not present default value acts as a fallback value. If you don't have any meaningful default value, pass null while creating context.

Note that Context value can be anything an object, function handle, string. Here we are using a string value.

2. Providing context

createContext() returns a context object which in itself doesn’t hold any information. Typically, you will enclose your higher component with the <Context.Provider> specifying the context value.

App.js

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ComponentA></ComponentA>
    </ThemeContext.Provider>
  );
};

export default App;

Now the ComponentA component and any components inside it, no matter how deep, will be able to access the passed context values.

ComponentA.js

import ComponentB from "./ComponentB";

const ComponentA = () => {
    return(
        <ComponentB />
    );
}    
export default ComponentA;

As you can see now there is no need to pass theme value using props.

ComponentB.js

import ComponentC from "./ComponentC";
const ComponentB = () => {
    return(
     <ComponentC />
    );
}    
export default ComponentB;

3. Accessing Context value.

Read the context value in the Component where you need it using useContext() hook which lets you read and subscribe to context from your component.

ComponentC.js

import { useContext } from "react";
import { ThemeContext } from "./Contexts";

const ComponentC = () => {
    const themeCtx = useContext(ThemeContext);
    return (
        <p>Current theme is- {themeCtx}</p>
    );
}    
export default ComponentC;

Passing dynamic data via context

In the above example value passed with Context provider is hardcoded but most of the times you will want it to be a dynamic value. To update context, you need to combine it with useState hook. Declare a state variable in the parent component and pass the current state down as the context value to the provider.

Here is the changed App.js where we have a checkbox to select theme, which is managed in a state variable named isDarkMode. In the context provider value is now changed dynamically using the current state.

import './App.css';
import { useState } from 'react';
import { ThemeContext } from './components/Examples/Contexts';
import ComponentA from './components/Examples/ComponentA';

function App() {
  const [isDarkMode, setIsDarkMode] = useState(0);
 
  return (

    <div>
      <input
        type="checkbox"
        checked={isDarkMode}
        onChange={e => setIsDarkMode(e.target.checked)}
      />
      Dark mode

      <hr />
      <ThemeContext.Provider value={isDarkMode? 'dark-mode' : 'light-mode'}>
        <ComponentA></ComponentA>
      </ThemeContext.Provider>
    </div>  
  );
}
export default App;
useContext hook React
useContext hook example

For example where context value is an object, check this post- React Context API With Examples

That's all for the topic React useContext Hook With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment