Context 提供一个无需为每层组件手动添加 props,就能在组件数间进行数据传递的方法。
使用场景
对一个组件树间而言是“全局”的数据,Context 为组件树提供这个”全局”数据。比如:
- 当前认证用户信息
- 网站主题
- 国际化,首选语言
官方示例:主题
import React from 'react'
// 为当前 theme 创建一个 context,默认值为 light
const ThemeContext = React.createContext('light')
class App extends React.Component {
render() {
// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。
return <ThemeContext.Provider value='dark'>
<Toolbar />
</ThemeContext.Provider>
}
}
class ThemeButton extends React.Component {
// 指定 contextType 读取当前的 theme context
// React 会往上找到最近的 theme Provider,然后使用它的值
// 在这个例子中,当前的 theme Provider 的值是 dark
static contextType = ThemeContext
render() {
return <Button theme={this.context} />
}
}
// 中间组件不需要往下传递 theme
function Toolbar() {
return <di>
<ThemeButton />
</div>
}
复制代码
API
创建 Context:React.createContext
const MyContext = React.createContext(defaultValue)
复制代码
创建一个 Context 对象。
只有当订阅了 Context 对象的组件没有在组件树中匹配到 Provider 时,defaultValue 才会生效。
提供 Context:Context.Provider
- Context.Provider 是一个组件,允许消费组件(要使用 context 的组件)订阅 context 的变化。
- Provider 提供一个 value 属性,覆盖 defaultValue,并传递给消费组件。
- Provider 可以嵌套使用,内层的 value 覆盖外层的 value
- Provider 的 value 发生变化时,内层的消费组件都会重新渲染。
- Provider 及其内部的消费组件都不受制于 shouldComponentUpdate 函数,因此当 消费组件在其祖先组件退出更新的情况下也能更新。
使用 Context 1:Class.contextType
在 class 组件中,把 Context 对象初始化给 class 组件的 contextType属性(该属性是定义在 class,是静态属性),然后在 class 内部通过 this.context 来使用 Provider 上的 value 值。
这个 context 在 class 组件内部任何生命周期中都能访问到。
两种初始化 class context 方法:
- 挂在 class 名上的方式
class MyClass extends React.Component {
render () {
const value = this.context
}
}
MyClass.contextType = MyContext
复制代码
- 通过 static 定义类的静态属性方式
class MyClass extends React.Component {
static contextType = MyContext
render () {
const value = this.context
}
}
复制代码
使用 Context 2:Context.Consumer
Context.Consumer 是一个组件,其子元素是一个返回 React 节点的函数,该函数的参数是最近的一个 Provider 的 value。
上述主题按钮可写成:
function ThemeButton() {
return <ThemeContext.Consumer>
{ value => <Button theme={value} />}
</ThemeContext.Consumer>
}
复制代码
开发工具:Context.displayName
Context.displayName 用于设置在 React.DevTools 中显示的组件名称。
Context 的多种应用形式
- 动态 context
- 在嵌套组件中更新 context,context 的 value 是一个对象格式,包含值和改变值的函数
const ThemeContext = React.createContext({
theme: 'dark',
toggleTheme: () => {}
})
复制代码
- 消费多个 context
注意事项
- 当 context 的值是一个对象时,容易触发意外的渲染,可以把状态提升至父组件进行集中管理。