How to Work with the React Context API and React useContext Hook

React context is primarily used when some data needs to be accessible by many components at different nesting levels. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

IN react we can pass data in top-down via props, but this will be hard to manage in some cases. So, context provides the best way to share value between components without passing props. You can use context to get the currently authenticated users, themes, etc.

To use context we need
1.) Context Provider
2.) Context Consumer. (To get data whenever you need).
So let’s take an example:

const Expenses = () => {
  const [expenses] = useState([
    {
      title: "First expense",
      description: "This is my first expense",
      status: false
    }
  ]);
  return (
    <div>
    <h1>Expenses</h1>
      {expenses.map(note => {
        return (
        <div>
          <h1>{expense.title}</h1>
          <h3>{expense.description}</h3>
          <p>{expense.status? "Paid!" : "Unpaid"}</p>
        </div>
        );
      })}
    </div>
  );
};

Just looking at this code, we can notice that we can break this component into smaller components, making our code cleaner and more maintainable. For example, we could create a component called Expense and inside that component, we would have three more components: Title, Description and Status.

const Expenses = () => {
  const [expenses] = useState([
    {
      title: "First expense",
      description: "This is my first expense",
      status: false
    }
  ]);
  return (
    <div>
      <h1>Expenses</h1>
      {expenses.map(({ title, description, done }) => {
        return <Expense title={title} description={description} status={status} />;
      })}
    </div>
  );
};

const Expense = ({ title, description, status}) => {
  return (
    <div>
      <Title title={title} />
      <Description description={description} />
      <status done={status} />
    </div>
  );
};

const Title = ({ title }) => {
  return <h1>{title}</h1>;
};

const Description = ({ description }) => {
  return <h3>{description}</h3>;
};

const Status= ({ status}) => {
  return <h3>{status}</h3>;
};

We now have a few components, and So we can maintain the reusability and maintainability of our example application. But, in the future, if this application grows in size and we feel the need to break these components into smaller components, we might have a problem.

Passing data through props over and over can cause problems for your application. Sometimes you might pass more props than you need or even forget to pass props that you do need, rename props through the components without notice, etc. If you’re passing data through props from the parent component to a fourth- or fifth-level component, you’re not reusing and writing maintainable code, and this might prejudice your application in the future.

This is what we call “prop-drilling”.That’s one of the main problems that Context API came to solve for us.

createContext

To start with the Context API, the first thing we need to do is create a context using the createContext function from React.

const ExpensesContext = createContext([]);

The createContext the function accepts an initial value, but this initial value is not required.

After creating your context, that context now has two React components that are going to be used: Provider and Consumer.

Provider

The Provider the component is going to be used to wrap the components that are going to have access to our context.
Let’s take an example. Make store/auth-context.js file.

import React from 'react';
const AuthContext = React.createContext({
  isLoggedIn: false
});
export default AuthContext;

Now provide context to the component. so in App.js

import React, { useState, useEffect } from 'react';
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import MainHeader from './components/MainHeader/MainHeader';
import AuthContext from './store/auth-context';
function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
    <AuthContext.Provider
      value={{
        isLoggedIn: isLoggedIn,
      }}
    >
      <MainHeader onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </AuthContext.Provider>
  );
}
export default App;

Now you can consume it using consumer.

import React from 'react';
import AuthContext from '../../store/auth-context';
const Navigation = (props) => {
  return (
    <AuthContext.Consumer>
      {(ctx) => {
        return (
          <nav className={classes.nav}>
            <ul>
              {ctx.isLoggedIn && (
                <li>
                  <a href="/">Users</a>
                </li>
              )}
              {ctx.isLoggedIn && (
                <li>
                  <a href="/">Admin</a>
                </li>
              )}
              {ctx.isLoggedIn && (
                <li>
                  <button onClick={props.onLogout}>Logout</button>
                </li>
              )}
            </ul>
          </nav>
        );
      }}
    </AuthContext.Consumer>
  );
};
export default Navigation;

What is the useContext hook?

Looking at the example above, the syntax for consuming context may look a bit strange to you.

Another way of consuming context became available in React 16.8 with the arrival of React hooks. We can now consume context with the useContext hook.

Instead of using render props, we can pass the entire context object to React.useContext() to consume context at the top of our component.

Here is the example above using the useContext hook:

import React, { useContext } from 'react';
const Navigation = (props) => {
  const ctx = useContext(AuthContext);
return (
    <nav className={classes.nav}>
      <ul>
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Users</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Admin</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <button onClick={props.onLogout}>Logout</button>
          </li>
        )}
      </ul>
    </nav>
  );
};
export default Navigation;

Conclusion

So, basically, context is sharing data “globally” for react component and using it when you need it.

I hope this gave you a better understanding of how to use React context. For more such articles, videos, and traveling vlogs you can subscribe to my YouTube channel.
https://www.youtube.com/c/CodeWithTravel

23