认识
一、认识
Context
提供了一个无需为每层组件手动添加 props
,就能在组件树间进行数据传递的方法。
1.1 prop drilling
在构建 React
应用程序时,在多层嵌套组件来使用另一个嵌套组件提供的数据。最简单的方法是将一个 prop
从每个组件一层层的传递下去,从源组件传递到深层嵌套组件,这叫做prop drilling
。
prop drilling
的主要缺点是原本不需要数据的组件变得不必要地复杂,并且难以维护。
为了避免prop drilling
,一种常用的方法是使用React Context
。通过定义提供数据的Provider
组件,并允许嵌套的组件通过Consumer
组件或useContext Hook
使用上下文数据。
二、问题
2.1 Context 使用后, 会暴露出那些问题呢?
-
通过
Provider
传递的状态, 如果不使用useMemo
跟useCallback
封装,以及Child
不使用memo
,在Provider
的组件re-render
时,所有使用到context
的地方都会被重新渲染。 -
如果
provider
传递的状态越来越多时,经常会因为provider
的其中一状态改变导致整颗子树都re-render
。要解决这个问题则是要把Provider
的状态切分的更细,用不同的Provider
分离状态。但如果分成多个Provider
,随着需要管理的状态越来越多,Provider
也会越来越多,介时也不好管理。
2.2 通过Provider
发布状态时,为什么要将value
提升到父节点的state
里?
答: 因为context
会使⽤参考标识(reference identity)
来决定何时进⾏渲染,这⾥可能会有⼀些陷阱,当provider
的⽗组件进⾏重渲染时,可能会在consumers
组件中触发意外的渲染。举个例⼦,当每⼀次Provider
重渲染时,以下的代码会重渲染所有下⾯的consumers
组件,因为value
属性总是被赋值为新的对象:
class App extends React.Component {
render() {
return (
<Provider value={{something:
'something'}}>
<Toolbar />
</Provider>
);
}
}
为了防⽌这种情况,将value
状态提升到⽗节点的state
⾥:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}