useContext Hook in React

When managing data between parent and child components, React gives us the ability to use something known as props to pass data down from parent to child. Props can only flow in one direction, from parent components to child components (and further down). When state changes occur on parent elements, React will re-render components that depend on those values.

Using props works well in most cases. However, when working in large applications with a large number of components in the component tree, props can become hard to maintain. Since props need to be declared in each and every component in the component tree.

useContext, in React, can help make things easier for us in situations like this.

Context

Context in React provides a way to pass data through a component tree without the need to prop-drill (i.e., pass props down manually at every level). We’ll go through a simple example to illustrate how this can be done.

To begin, we first need to create the Context object with the createContext() function.

import React, { createContext } from "react";

const Context = createContext();

To have context available in the entire component tree, we need to wrap the parent component markup with the Context provider to have all child components subscribe to Context changes.

If we have an <App /> component that acts as the parent component of the application, using the Context provider would look something can look something like the following:

import React, { createContext } from "react";

const Context = createContext();

const App = () => {
  return <Context.Provider>/* ... */</Context.Provider>;
};

When declaring the Context provider, we’ll go ahead and specify the context value in the value prop of <Context.Provider>. This is how we’ll provide some initial data for our example.

import React, { createContext } from "react";

const Context = createContext();

const App = () => {
  return (
    <Context.Provider value={{ data: "Data from context!" }}>
      /* ... */
    </Context.Provider>
  );
};

We’ll now assume <App /> is to render a child component named <Child />.

import React, { createContext } from "react";

const Context = createContext();

const Child = () => {
  return <div>This is the child component!</div>;
};

const App = () => {
  return (
    <Context.Provider>
      <Child />
    </Context.Provider>
  );
};

React JSX

We can have the <Child /> component retrieve the current context value with the help of the useContext Hook.

Props vs. Context

When should one decide to use props vs. context? There are pros and cons to each approach.

With props:

  • We have a clearly defined pattern of passing data one level at a time without the need to leverage any additional API or Hooks (pro).
  • However, the pattern of passing props data one level at a time can be cumbersome if we were to have a large number of components in our component hierarchy tree (con).

With Context:

  • We have the capability to have a child component access data from a parent component many levels above without the need to have this data passed down each level (pro).
  • However, Context can make debugging difficult if bugs arise. Debugging is more likely to be difficult if we had numerous different Context objects and providers in a large-scale application (con).

Context is best used for application-wide client data. Things like theme information, locale/language preferences, user authentication information, etc. are best kept in Context since any component within an application may have the need to access this data at any time.

Props is best used when data needs to be isolated to a few set of components only.