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();
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>
);
}
Here is what we're looking at:
Home
Results
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>
);
}
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>
)
}
This is the results page, and it is using the useContext function to grab a value out of "UserContext", which it is then displaying:
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".
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>
)
}
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)
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.I like the color of your code.
great color
Thanks for the brilliant explanation, the best example I've ever seen. Definitely bookmarked.
It's like using normal state functions but eliminating the pain of passing state as props (or prop drilling).
So helpful - thanks, Kon!!