Understanding Context in React JS using React Hooks.

Hello everyone,

In this blog, I have tried to explain how to use the react hook useContext in our react application. While creating an application, we create a hierarchy of components and so we have to pass common data elements from parent to child components as props. This could be very cumbersome to manage in the case of high-end applications where data is required by multiple child elements within the application. To handle this issue React provides a hook called useContext. But before we go deeper into useContext let's first understand what is meant by Context in React.

Context in React

In React, Context provides a way to pass data through the component tree without having to pass props down manually at every level. With Context we can create data that is globally available to a tree of React components like user authentication details, theme or language, etc. Using context we can avoid passing data via props to different components of a React component tree. I will explain this in detail with an example.

A sample code to show a React Component tree

Our Interpretation of the above code snippet

  • As you can see, in the above code I have defined three function components, Parent Component, Child Component, and Sub Child Component. Value of theme variable is declared in state variable inside parent component and passed as props value to Child Component.
  • A toggle button is present in the parent component to toggle the state of the theme variable.
  • Even though the value of the theme is not required in the Child component still we have to store the props value inside the Child Component. Child Component makes a call to Sub Child component and passes the theme variable as props to it.
  • Inside the Sub Child Component we can see the effect of the toggle on the background color of the paragraph.
  • We have explicitly passed the 'props' data to even those components which do not use it, only to make the data available to the components available in the hierarchy below. We are maintaining the overhead of constantly passing the 'props' data throughout the entire Hierarchy.

useContext

To resolve the issue explained above we will use the useContext hook. But before we begin we will create a Context using Context API.

Check the code for better understanding.

I have created a new context named 'AppContext' using React.createContext(). Check the below code snippet.

import React from 'react';
const AppContext= React.createContext();

The createContext returns an object with a Provider and a consumer, as shown below.

const { Provider, Consumer } = AppContext;

The Provider component is what makes the state available to all child components, no matter how deeply nested they are within the component tree. The Provider component receives a value prop, in which we pass our current value/values.

The new context is created inside a separate file with the name context.js. The code snippet shown below is for the same.

import React, { useState } from 'react';
const AppContext = React.createContext();

const AppProvider=({children})=>{
const [theme,setTheme] = useState(false);

  return(
    <>
      <AppContext.Provider value={{theme,setTheme}}>
        {children}
      </AppContext.Provider>
    </> 
  )

}

export { AppContext, AppProvider };
  1. First we have to create, a new context with the name AppContext.
  2. Then we create a component with the name AppProvider and pass 'children' as prop value.
  3. AppContext.Provider is the Provider component of AppContext which was created when I have declared const AppContext = React.createContext().
  4. 'theme' and 'setTheme' are passed as props to 'value'.
  5. Since we are not rendering any component from inside AppContext.Provider, so by convention I have provided 'children' as prop value to AppProvider and rendered the same, from inside the tags.
  6. According to React doc, 'children' represents child elements that are not yet declared but may be rendered in time. So we can contain those upcoming components inside {children}.

A code snippet is attached below to better explain the concept of children in React.

const Foo = props => (
  <div>
    <p>I'm {Foo.name}</p>
    <p>abc is: {props.abc}</p>

    <p>I have {props.children.length} children.</p>
    <p>They are: {props.children}.</p>
    <p>{Array.isArray(props.children) ? 'My kids are an array.' : ''}</p>
  </div>
);

const Baz = () => <span>{Baz.name} and</span>;
const Bar = () => <span> {Bar.name}</span>;

invoke/call/render Foo:

<Foo abc={123}>
  <Baz />
  <Bar />
</Foo>

Output:

img.png

  1. In index.js we import AppProvider and wrap the component under tags. As I have provided 'children' as prop, the app component is rendered from inside the tags declared in context.js. Hence, children = App component. In the End, we will export the AppContext and AppProvider from context.js.
  2. In index.js we import AppProvider and wrap the component under tags. As I have provided 'children' as prop, the app component is rendered from inside the tags declared in context.js. Hence, children = App component.

Check the below code snippet for better understanding.

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
import {AppProvider} from './context';

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <AppProvider>
      <App />
    </AppProvider>
  </StrictMode>,
  rootElement
);
  1. In App.js parent, child, and subChild component are mentioned together for easier understanding. As you can see that this time I did not pass any prop value from parent to subChild component via Child component.
  2. I have used useContext to call AppContext from context.js to Parent and SubChild component.
  3. In the Parent component, setTheme toggles the value of theme using the button, and the same is reflected over the background of the paragraph inside SubChild.

An alternate approach would be to directly declare the AppContext inside the App component and render Child Component. This removes the need to wrap the App component inside AppProvider in index.js. Check the code for better understanding.

Instead of {children} I have rendered from inside tags.

Conclusion

useContext is an amazing way to remove the overhead of passing the data via props to the different levels in the hierarchy even if it is not required. I have shown two ways of using context API, by either declaring the context in a separate file and wrapping the App component inside AppProvider in index.js or we can directly create the context inside the parent and render the child component. It's up to the user to choose whichever way they seem suitable. In the end, I would say that the useContext hook provides a nice interface for consuming context, but that interface is so much better than the original context consumer interface. Next time try to using context in your application make sure to give useContext a try.