谈谈 Context
是什么
- Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
- 需要注意场景是否应该使用 Context,因为这样会使用组件复用性变差,或许 render props 可以解决问题。
怎么用
- React.createContext 创建一个上下文的容器, defaultValue 可以设置共享的默认数据。
const {Provider, Consumer} = React.createContext(defaultValue);
- Provider 数据生产者
用于生产共享数据的地方,value 即为放置共享的数据。
<Provider value={/*共享的数据*/}>
/*里面可以渲染对应的内容*/
</Provider>
- Consumer 数据消费者
消费供应商 Provider 产生数据。Consumer 需要嵌套在生产者下面,通过回调的方式拿到共享的数据源,当然也可以单独使用,那就只能消费到上文提到的 defaultValue。
<Consumer>
{value => /*根据上下文 进行渲染相应内容*/}
</Consumer>
示例
import React, { createContext } from "react";
// 英文状态
const enStrings = {
submit: "Submit",
cancel: "Cancel"
};
// 中文状态
const cnStrings = {
submit: "提交",
cancel: "取消"
};
// 创建一个数据提供与数据消费者,同时可以赋初值
const {
Provider, // 数据提供
Consumer // 数据消费者
} = createContext(enStrings);
// 父组件数据提供者
class App extends React.Component {
state = { locale: cnStrings };
// 切换语言
toggleLocale = () => {
const locale = this.state.locale === enStrings ? cnStrings : enStrings;
this.setState({ locale });
};
render() {
return (
<Provider value={this.state.locale}>
<button onClick={this.toggleLocale}>切换语言</button>
<Child />
</Provider>
);
}
}
// 子组件消费数据:Consumer接受数据
class Child extends React.Component {
render() {
return (
<Consumer>
{(locale) => {
console.log("locale", locale);
return (
<div>
<button>{locale.cancel}</button>
<button>{locale.submit}</button>
</div>
);
}}
</Consumer>
);
}
}
export default App;
Context 缺点
- context 相当于全局变量,难以追溯数据源
- 耦合度高,即不利于组件复用也不利于测试
- 在老版 Context(v16.3 之前):当 props 改变或者 setState 被调用,生成新的 context,但是 shouldComponentUpdate 返回的 false 会 block 住 context,导致没有更新。因此新版 Context 改成了传播不受限制于 shouldComponentUpdate,在顶层组件跳过更新时也能更新。