https://daveceddia.com/usecontext-hook/


How the useContext Hook Works

The useContext Hook

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

How can I implement this if the provider and the consumer are in different files?

D
Dave Ceddia
0 points
12 months ago

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

+ Recent posts