DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป is a community of 964,423 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Konstantin Stanmeyer
Konstantin Stanmeyer

Posted on

An Intro to useContext in React.js

An aspect of React that I never like is the transfer of state values between components, and requiring props to be passed to both give values of state, as well as update them. The useContext hook can make this process a slight bit easier by allowing you to manage state globally, and for nested components especially, they have an easier time without the need to pass props.

How to Begin

The most conventional approach to using this hook is to initialize the context (global state value), and give it the ability to pass a value down to components. This first step to initialize UserContext as a variable is all done within its own file, for me, named CreateContext.js:

import { createContext } from "react";

export const UserContext = createContext();
Enter fullscreen mode Exit fullscreen mode

This is all the required code in that file. Now we can go to our page, which in my case, my App.js is structured as so:

function App() {
  return (
    <Router>
      <div className="page">
        <div>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/results/">Results</Link>
          </li>
        </div>
        <Routes>
            <Route exact path="/" element={
            <Home />
            }/>
            <Route path="/results" element={
            <Results />
            }/>
        </Routes>
      </div>
    </Router>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here is what we're looking at:

Home

Image description

Results

Image description

For my simple example, the idea is to create an input from the input-box, set it to the global state value, then access it from our results page. Here is how to initialize that value, then wrap it around the components we want to access that information:

import React, { useState } from 'react';
import Home from './Home';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import Results from './Results';
import { UserContext } from './CreateContext';

function App() {
  const [value, setValue] = useState("default")

  return (
    <Router>
      <div className="page">
        <div>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/results/">Results</Link>
          </li>
        </div>
        <UserContext.Provider value={{ value, setValue }}>
          <Routes>
              <Route exact path="/" element={
                <Home />
              }/>
              <Route path="/results" element={
                <Results />
              }/>
          </Routes>
        </UserContext.Provider>
      </div>
    </Router>
  );
}
Enter fullscreen mode Exit fullscreen mode

We are at the highest level of the application, and the highest place we want to access the information. We have passed along a value to the global state, which has been set to the variable "value", meaning it is initialized as "default".

Now, if we want to access that value, we can do it as such:

import { useContext } from "react";
import { UserContext } from './CreateContext';

export default function Results(){
    const { value } = useContext(UserContext)

    return(
        <div>
            <p>Results: {value}</p>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

This is the results page, and it is using the useContext function to grab a value out of "UserContext", which it is then displaying:

Image description

Now, to update this value, I can go to my Home page, and change the input field, which has been set to the same global state value, "default".

Image description

Here is how I am grabbing that value:

import { useContext } from "react";
import { UserContext } from './CreateContext';

export default function Home(){
    const { value, setValue } = useContext(UserContext);

    return(
        <div>
            <p>Enter a value: </p>
            <input
                type="text"
                placeholder="enter value..."
                value={value}
                onChange={(e) => setValue(e.target.value)}
            />
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

We are also able to update it with this function, with the onChange utilizing the setter function. As you can see, this step looks almost identical to useState. We are using the hook function to grab a value, and de-structure it to allow us to both use what's stored, and set it by passing the setter function a new value.

Top comments (5)

Collapse
 
bmw2621 profile image
Ben Winchester • Edited on

To cut down on imports in consumer files (1. import the context, 2. import useContext), export a hook from your provider file instead of the context.

import { createContext, useContext } from "react";

const UserContext = createContext();
export const useUserContext = useContext(UserContext)

/* ... */
Enter fullscreen mode Exit fullscreen mode
import { useUserContext } from '../context/UserContext';

const ConsumingComponent = () => {
   const { value, setValue } = useUserContext()

  /* ... */
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jpucci26 profile image
Jake Pucci

I like the color of your code.
great color

Collapse
 
olsard profile image
olsard

Thanks for the brilliant explanation, the best example I've ever seen. Definitely bookmarked.

Collapse
 
vishwastyagi profile image
Vishwas Tyagi

It's like using normal state functions but eliminating the pain of passing state as props (or prop drilling).

Collapse
 
ericahashert profile image
Erica Hashert

So helpful - thanks, Kon!!

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

โญ๏ธ๐ŸŽ€ JavaScript Visualized: Promises & Async/Await

async await