https://daveceddia.com/usecontext-hook/
How the useContext Hook Works
There’s a running theme between all these new React Hooks: almost all of them exist to make function components as powerful as class Components.
The useContext
hook is a little different though. It just makes things nicer.
In case you haven’t heard of React’s Context API, it’s a way to pass data deeply throughout your app without having to manually pass props down through multiple levels. It can be a good alternative to tools like Redux when all you need to do is pass data around, and you can learn more about Context and how it compares to Redux here.
In this post we’ll look at how useContext
makes Context a little easier to consume.
The Standard Way
The typical way to use the Context API looks like this:
import React from "react";
import ReactDOM from "react-dom";
// Create a Context
const NumberContext = React.createContext();
// It returns an object with 2 values:
// { Provider, Consumer }
function App() {
// Use the Provider to make a value available to all
// children and grandchildren
return (
<NumberContext.Provider value={42}>
<div>
<Display />
</div>
</NumberContext.Provider>
);
}
function Display() {
// Use the Consumer to grab the value from context
// Notice this component didn't get any props!
return (
<NumberContext.Consumer>
{value => <div>The answer is {value}.</div>}
</NumberContext.Consumer>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
Here’s the example on CodeSandbox.
See how we get the value inside the Display
component? We have to wrap our content in a NumberContext.Consumer
and use the render props pattern – passing a function as a child – to retrieve the value and display it.
This works fine, and “render props” is a great pattern for passing dynamic data around, but it does introduce some unnecessary nesting and some cognitive overhead (especially if you’re not used to it).
I cover the Context API in more depth here.
The useContext Way
Let’s rewrite the Display
using the new useContext
hook and see what it looks like:
// import useContext (or we could write React.useContext)
import React, { useContext } from 'react';
// ...
function Display() {
const value = useContext(NumberContext);
return <div>The answer is {value}.</div>;
}
That’s all there is to it. Call useContext
, pass in the context object you got from React.createContext
, and out pops the value. Easier to read, right?
The only thing you want to watch out for is that you have to pass the whole context object to useContext
– not just the consumer! React will warn you if you forget, but try to rememeber, eh?
Nested Consumers
You might have a case where your component needs to receive data from multiple parent contexts, leading to code like this:
function HeaderBar() {
return (
<CurrentUser.Consumer>
{user =>
<Notifications.Consumer>
{notifications =>
<header>
Welcome back, {user.name}!
You have {notifications.length} notifications.
</header>
}
}
</CurrentUser.Consumer>
);
}
This is an awful lot of nesting just to receive 2 values. Here’s what it can look like with useContext
:
function HeaderBar() {
const user = useContext(CurrentUser);
const notifications = useContext(Notifications);
return (
<header>
Welcome back, {user.name}!
You have {notifications.length} notifications.
</header>
);
}
Much easier to read.
If you want to connect provider and consumer in different file
Export the Context from where it's created, and import it wherever you need the Provider and Consumer. If you have an egghead membership I have a lesson describing how to do this here.
context.js
import { createContext } from 'react';
const Context = createContext();
export default Context
app.js
import React, { useState } from 'react';
import './App.css';
import Display from './components/Display';
import Context from './components/Context';
function App() {
return (
<div className="App">
<body>
<Context.Provider value={42}>
<div>
<Display />
</div>
</Context.Provider>
</body>
</div>
);
}
export default App;
Display.js
import React from "react";
import Context from "./Context";
// It returns an object with 2 values:
// { Provider, Consumer }
function Display() {
// Use the Consumer to grab the value from context
// Notice this component didn't get any props!
return (
<Context.Consumer>
{value => <div>The answer is {value}.</div>}
</Context.Consumer>
);
}
export default Display;
'frameworks > react' 카테고리의 다른 글
3 Reasons to useReducer() over useState() (0) | 2020.03.30 |
---|---|
How to Use the useReducer Hook (0) | 2020.03.29 |
How the useEffect Hook Works (0) | 2020.03.28 |
Using the Effect Hook (0) | 2020.03.28 |
Using the State Hook (0) | 2020.03.28 |
How can I implement this if the provider and the consumer are in different files?