聊一聊我对 React Context 的理解以及应用(2)

class Header extends React.Component { render () { return ( <Title>Hello React Context API</Title> ); } } class Title extends React.Component { render () { return ( <ThemeContext.Consumer> {context => ( <h1 style={{background: context.background, color: context.color}}> {this.props.children} </h1> )} </ThemeContext.Consumer> ); } }

<Consumer />的children必须是一个函数,通过函数的参数获取<Provider />提供的Context。

可见,Context的新API更加贴近React的风格。

几个可以直接获取Context的地方

实际上,除了实例的context属性(this.context),React组件还有很多个地方可以直接访问父组件提供的Context。比如构造方法:

constructor(props, context)

比如生命周期:

componentWillReceiveProps(nextProps, nextContext)

shouldComponentUpdate(nextProps, nextState, nextContext)

componetWillUpdate(nextProps, nextState, nextContext)

对于面向函数的无状态组件,可以通过函数的参数直接访问组件的Context。

const StatelessComponent = (props, context) => ( ...... )

以上是Context的基础,更具体的指南内容可参见这里

我对Context的理解

OK,说完基础的东西,现在聊一聊我对React的Context的理解。

把Context当做组件作用域

使用React的开发者都知道,一个React App本质就是一棵React组件树,每个React组件相当于这棵树上的一个节点,除了App的根节点,其他每个节点都存在一条父组件链。

聊一聊我对 React Context 的理解以及应用

例如上图,<Child />的父组件链是<SubNode /> -- <Node /> -- <App />,<SubNode />的父组件链是<Node /> -- <App />,<Node />的父组件链只有一个组件节点,就是<App />。

这些以树状连接的组件节点,实际上也组成了一棵Context树,每个节点的Context,来自父组件链上所有组件节点通过getChildContext()所提供的Context对象组合而成的对象。

聊一聊我对 React Context 的理解以及应用


有了解JS作用域链概念的开发者应该都知道,JS的代码块在执行期间,会创建一个相应的作用域链,这个作用域链记录着运行时JS代码块执行期间所能访问的活动对象,包括变量和函数,JS程序通过作用域链访问到代码块内部或者外部的变量和函数。

假如以JS的作用域链作为类比,React组件提供的Context对象其实就好比一个提供给子组件访问的作用域,而Context对象的属性可以看成作用域上的活动对象。由于组件的Context由其父节点链上所有组件通过getChildContext()返回的Context对象组合而成,所以,组件通过Context是可以访问到其父组件链上所有节点组件提供的Context的属性。

所以,我借鉴了JS作用域链的思路,把Context当成是组件的作用域来使用。

关注Context的可控性和影响范围

不过,作为组件作用域来看待的Context与常见的作用域的概念 (就我个人目前接触到的编程语言而言) 是有所区别的。我们需要关注Context的可控性和影响范围。

在我们平时的开发中,用到作用域或者上下文的场景是很常见,很自然,甚至是无感知的,然而,在React中使用Context并不是那么容易。父组件提供Context需要通过childContextTypes进行“声明”,子组件使用父组件的Context属性需要通过contextTypes进行“申请”,所以,我认为React的Context是一种“带权限”的组件作用域。

这种“带权限”的方式有何好处?就我个人的理解,首先是保持框架API的一致性,和propTypes一样,使用声明式编码风格。另外就是,可以在一定程度上确保组件所提供的Context的可控性和影响范围。

React App的组件是树状结构,一层一层延伸,父子组件是一对多的线性依赖。随意的使用Context其实会破坏这种依赖关系,导致组件之间一些不必要的额外依赖,降低组件的复用性,进而可能会影响到App的可维护性。

聊一聊我对 React Context 的理解以及应用

通过上图可以看到,原本线性依赖的组件树,由于子组件使用了父组件的Context,导致<Child />组件对<Node />和<App />都产生了依赖关系。一旦脱离了这两个组件,<Child />的可用性就无法保障了,减低了<Child />的复用性。

聊一聊我对 React Context 的理解以及应用


内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsdgxg.html