何时使用context
Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 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>
);
}
}
// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。
API
React.createContext
创建一个 Context
对象。当 React 渲染一个订阅了这个 Context
对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider
中读取到当前的 context
值。
只有当组件所处的树中没有匹配到 Provider
时,其 defaultValue
参数才会生效。这有助于在不使用 Provider
包装组件的情况下对组件进行测试。注意:将 undefined
传递给 Provider
时,消费组件的 defaultValue
不会生效。
const MyContext = React.createContext(defaultValue);
Context.Provider
每个 Context
对象都会返回一个 Provider React
组件,它允许消费组件订阅 context
的变化。
Provider
接收一个 value
属性,传递给消费组件。一个 Provider
可以和多个消费组件有对应关系。多个 Provider
也可以嵌套使用,里层的会覆盖外层的数据。
当 Provider
的 value
值发生变化时,它内部的所有消费组件都会重新渲染。Provider
及其内部 consumer
组件都不受制于 shouldComponentUpdate
函数,因此当 consumer
组件在其祖先组件退出更新的情况下也能更新。
通过新旧值检测来确定变化,使用了与 Object.is 相同的算法。
<MyContext.Provider value={/* 某个值 */}>
Context.Consumer
这需要函数作为子元素(function as a child
)这种做法。这个函数接收当前的 context
值,返回一个 React
节点。传递给函数的 value
值等同于往上组件树离这个 context
最近的 Provider
提供的 value
值。如果没有对应的 Provider
,value
参数等同于传递给 createContext()
的 defaultValue
。
<MyContext.Consumer>
{value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>