惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
S
Secure Thoughts
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
N
News | PayPal Newsroom
Application and Cybersecurity Blog
Application and Cybersecurity Blog
O
OpenAI News
S
Security @ Cisco Blogs
宝玉的分享
宝玉的分享
Hacker News: Ask HN
Hacker News: Ask HN
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
TaoSecurity Blog
TaoSecurity Blog
Help Net Security
Help Net Security
Latest news
Latest news
NISL@THU
NISL@THU
S
Security Affairs
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 聂微东
AI
AI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Recent Announcements
Recent Announcements
P
Privacy & Cybersecurity Law Blog
小众软件
小众软件
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
AWS News Blog
AWS News Blog
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
I
InfoQ
Schneier on Security
Schneier on Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
The Exploit Database - CXSecurity.com
IT之家
IT之家
T
Threatpost
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
腾讯CDC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
News and Events Feed by Topic
L
LINUX DO - 最新话题
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
H
Heimdal Security Blog
S
SegmentFault 最新的问题

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback() 5 JavaScript Scope Gotchas
A Guide to React Context and useContext() Hook
Dmitri Pavlutin · 2021-09-02 · via Dmitri Pavlutin Blog

React context provides data to components no matter how deep they are in the components tree. The context is used to manage global data, e.g. global state, theme, services, user settings, and more.

In this post, you'll learn how to use the context concept in React.

Table of Contents

  • 1. How to use the context
    • A. Creating the context
    • B. Providing the context
    • C. Consuming the context
  • 2. When do you need context?
  • 3. Use case: global user name
    • 3.1 Context to the rescue
    • 3.2 When context changes
  • 4. Updating the context
  • 5. Conclusion

1. How to use the context

Using the context in React requires 3 simple steps: creating the context, providing the context, and consuming the context.

A. Creating the context

The built-in factory function createContext(default) creates a context instance:


// context.js

import { createContext } from 'react';

export const Context = createContext('Default Value');


The factory function accepts one optional argument: the default value.

B. Providing the context

Context.Provider component available on the context instance is used to provide the context to its child components, no matter how deep they are.

To set the value of context use the value prop available on the <Context.Provider value={value} />:


import { Context } from './context';

function Main() {

const value = 'My Context Value';

return (

<Context.Provider value={value}>

<MyComponent />

</Context.Provider>

);

}


Again, what's important here is that all the components that'd like later to consume the context have to be wrapped inside the provider component.

If you want to change the context value, simply update the value prop.

C. Consuming the context

Consuming the context can be performed in 2 ways.

The first way, the one I recommend, is to use the useContext(Context) React hook:


import { useContext } from 'react';

import { Context } from './context';

function MyComponent() {

const value = useContext(Context);

return <span>{value}</span>;

}


Open the demo.

The hook returns the value of the context: value = useContext(Context). The hook also makes sure to re-render the component when the context value changes.

The second way is by using a render function supplied as a child to Context.Consumer special component available on the context instance:


import { Context } from './context';

function MyComponent() {

return (

<Context.Consumer>

{value => <span>{value}</span>}

</Context.Consumer>

);

}


Open the demo.

Again, in case the context value changes, <Context.Consumer> will re-call its render function.

React context

You can have as many consumers as you want for a single context. If the context value changes (by changing the value prop of the provider <Context.Provider value={value} />), then all consumers are immediately notified and re-rendered.

If the consumer isn't wrapped inside the provider, but still tries to access the context value (using useContext(Context) or <Context.Consumer>), then the value of the context would be the default value argument supplied to createContext(defaultValue) factory function that had created the context.

2. When do you need context?

The main idea of using the context is to allow your components to access global data and re-render when that global data is changed. Context solves the props drilling problem: when you have to pass down props from parents to children.

You can hold inside the context:

  • global state
  • theme
  • application configuration
  • authenticated user name
  • user settings
  • preferred language
  • a collection of services

On the other side, you should think carefully before deciding to use context in your application.

First, integrating the context adds complexity. Creating a context, wrapping everything in a provider, and using the useContext() in every consumer — increases complexity.

Secondly, adding context complicates unit testing of components. During testing, you'll have to wrap the consumer components into a context provider. Including the components that are indirectly affected by the context — the ancestors of context consumers!

3. Use case: global user name

The simplest way to pass data from a parent to a child component is when the parent assigns props to its child component:


function Application() {

const userName = "John Smith";

return <UserInfo userName={userName} />;

}

function UserInfo({ userName }) {

return <span>{userName}</span>;

}


The parent component <Application /> assigns userName data to its child component <UserInfo name={userName} /> using the userName prop.

That's the usual way how data is passed using props. You can use this approach without problems.

The situation changes when <UserInfo /> component isn't a direct child of <Application />, but is buried somewhere deeper.

For example, let's say that <Application /> component (the one having the global data userName) renders <Layout /> component, which in turn renders <Header /> component, which in turn finally renders <UserInfo /> component (that'd like to access userName).

Here's how such a structuring would look:


function Application() {

const userName = "John Smith";

return (

<Layout userName={userName}>

Main content

</Layout>

);

}

function Layout({ children, userName }) {

return (

<div>

<Header userName={userName} />

<main>

{children}

</main>

</div>

)

}

function Header({ userName }) {

return (

<header>

<UserInfo userName={userName} />

</header>

);

}

function UserInfo({ userName }) {

return <span>{userName}</span>;

}


Open the demo.

You can see the problem: because <UserInfo /> component renders deep down in the tree, all the parent components (<Layout /> and <Header />) have to pass the userName prop.

This problem is also known as props drilling.

React context is a possible solution. Let's see how to apply it in the next section.

3.1 Context to the rescue

As a quick reminder, applying the React context requires 3 actors: the context, the provider extracted from the context, and the consumer.

Here's how the sample application would look when applying the context to it:


import { useContext, createContext } from 'react';

const UserContext = createContext('Unknown');

function Application() {

const userName = "John Smith";

return (

<UserContext.Provider value={userName}>

<Layout>

Main content

</Layout>

</UserContext.Provider>

);

}

function Layout({ children }) {

return (

<div>

<Header />

<main>

{children}

</main>

</div>

);

}

function Header() {

return (

<header>

<UserInfo />

</header>

);

}

function UserInfo() {

const userName = useContext(UserContext);

return <span>{userName}</span>;

}


Open the demo.

Let's look into more detail at what has been done.

First, const UserContext = createContext('Unknown') creates the context that's going to hold the user name information.

Second, inside the <Application /> component, the application's child components are wrapped inside the user context provider: <UserContext.Provider value={userName}>. Note that the value prop of the provider component is important: this is how you set the value of the context.

Finally, <UserInfo /> becomes the consumer of the context by using the built-in useContext(UserContext) hook. The hook is called with the context as an argument and returns the user name value.

<Layout /> and <Header /> intermediate components don't have to pass down the userName prop. That is the great benefit of the context: it removes the burden of passing down data through the intermediate components.

3.2 When context changes

When the context value is changed by altering value prop of the context provider (<Context.Provider value={value} />), then all of its consumers are notified and re-rendered.

For example, if I change the user name from 'John Smith' to 'Smith, John Smith', then <UserInfo /> consumer immediately re-renders to display the latest context value:


import { createContext, useEffect, useState } from 'react';

const UserContext = createContext('Unknown');

function Application() {

const [userName, setUserName] = useState('John Smith');

useEffect(() => {

setTimeout(() => {

setUserName('Smith, John Smith');

}, 2000);

}, []);

return (

<UserContext.Provider value={userName}>

<Layout>

Main content

</Layout>

</UserContext.Provider>

);

}

// ...


Open the demo.

Open the demo and you'll see 'John Smith' (context value) displayed on the screen. After 2 seconds, the context value changes to 'Smith, John Smith', and correspondingly the screen is updated with the new value.

The demo shows that <UserInfo /> component, the consumer that renders the context value on the screen, re-renders when the context value changes.


function UserInfo() {

const userName = useContext(UserContext);

return <span>{userName}</span>;

}


4. Updating the context

The React Context API is stateless by default and doesn't provide a dedicated method to update the context value from consumer components.

But this can be easily implemented by integrating a state management mechanism (like useState() or useReducer() hooks), and providing an update function right in the context next to the value itself.

In the following example, <Application /> component uses useState() hook to manage the context value.


import { createContext, useState, useContext, useMemo } from 'react';

const UserContext = createContext({

userName: '',

setUserName: () => {},

});

function Application() {

const [userName, setUserName] = useState('John Smith');

const value = useMemo(

() => ({ userName, setUserName }),

[userName]

);

return (

<UserContext.Provider value={value}>

{useMemo(() => (

<>

<UserNameInput />

<UserInfo />

</>

), [])}

</UserContext.Provider>

);

}

function UserNameInput() {

const { userName, setUserName } = useContext(UserContext);

const changeHandler = event => setUserName(event.target.value);

return (

<input

type="text"

value={userName}

onChange={changeHandler}

/>

);

}

function UserInfo() {

const { userName } = useContext(UserContext);

return <span>{userName}</span>;

}


Open the demo.

<UserNameInput /> consumer reads the context value, from where userName and setUserName are extracted. The consumer then can update the context value by invoking the update function setUserName(newContextValue).

<UserInfo /> is another consumer of the context. When <UserNameInput /> updates the context, this component is updated too.

Note that <Application /> memoizes the context value. Memoization keeps the context value object unchanged as long as userName remains the same, preventing re-rendering of consumers every time the <Application /> re-renders.

Otherwise, without memoization, const value = { userName, setUserName } would create different object instances during re-rendering of <Application />, triggering re-rendering in context consumers. See more about referential equality of objects.

5. Conclusion

The context in React lets you supply child components with global data, no matter how deep they are in the components tree.

Using the context requires 3 steps: creating, providing, and consuming the context.

When integrating the context into your application, consider that it adds a good amount of complexity. Sometimes drilling the props through 2-3 levels in the hierarchy isn't a big problem.

What use cases of React context do you know?