对react的context的研究

Context被翻译为上下文,在编程领域,这是一个经常会接触到的概念,React中也有。

在React的官方文档中,Context被归类为高级部分(Advanced),属于React的高级API,但官方并不建议在稳定版的App中使用Context。

不过,这并非意味着我们不需要关注 Context。事实上,很多优秀的React组件都通过Context来完成自己的功能,比如react-redux的 ,就是通过 Context提供一个全局态的 store,拖拽组件react-dnd,通过 Context在组件中分发DOM的Drag和Drop事件,路由组件react-router通过 Context管理路由状态等等。在React组件开发中,如果用好 Context,可以让你的组件变得强大,而且灵活。
 简单说就是,当你不想在组件树中通过逐层传递 props或者 state的方式来传递数据时,可以使用 Context来实现跨层级的组件数据传递。
 
使用 Context,可以跨越组件进行数据传递。
 
对于父组件,也就是 Context生产者,需要通过一个静态属性 childContextTypes声明提供给子组件的 Context对象的属性,并实现一个实例 getChildContext方法,返回一个代表 Context的纯对象 (plain object) 。

而对于 Context的消费者,通过如下方式访问父组件提供的 Context
 

子组件需要通过一个静态属性contextTypes声明后,才能访问父组件Context对象的属性,否则,即使属性名没写错,拿到的对象也是undefined

对于无状态子组件(Stateless Component),可以通过如下方式访问父组件的Context

 

通过静态方法React.createContext()创建一个Context对象,这个Context对象包含两个组件,

几个可以直接获取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当做组件作用域

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

通过 Context暴露数据或者API不是一种优雅的实践方案,尽管react-redux是这么干的。因此需要一种机制,或者说约束,去降低不必要的影响。

通过childContextTypescontextTypes这两个静态属性的约束,可以在一定程度保障,只有组件自身,或者是与组件相关的其他子组件才可以随心所欲的访问Context的属性,无论是数据还是函数。因为只有组件自身或者相关的子组件可以清楚它能访问Context哪些属性,而相对于那些与组件无关的其他组件,无论是内部或者外部的 ,由于不清楚父组件链上各父组件的childContextTypes“声明”了哪些Context属性,所以没法通过contextTypes“申请”相关的属性。所以我理解为,给组件的作用域Context“带权限”,可以在一定程度上确保Context的可控性和影响范围。

在开发组件过程中,我们应该时刻关注这一点,不要随意的使用Context

  • App级的数据共享

App根节点组件提供的Context对象可以看成是App级的全局作用域,所以,我们利用App根节点组件提供的Context对象创建一些App级的全局数据。现成的例子可以参考react-redux,以下是组件源码的核心实现:

export function createProvider(storeKey = 'store', subKey) { const subscriptionKey = subKey || `${storeKey}Subscription` class Provider extends Component { getChildContext() { return { [storeKey]: this[storeKey], [subscriptionKey]: null } } constructor(props, context) { super(props, context) this[storeKey] = props.store; } render() { return Children.only(this.props.children) } } // ...... Provider.propTypes = { store: storeShape.isRequired, children: PropTypes.element.isRequired, } Provider.childContextTypes = { [storeKey]: storeShape.isRequired, [subscriptionKey]: subscriptionShape, } return Provider } export default createProvider()
App的根组件用 组件包裹后,本质上就为App提供了一个全局的属性 store,相当于在整个App范围内,共享 store属性。当然, 组件也可以包裹在其他组件中,在组件级的全局范围内共享 store
组件级的数据共享
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

你可能感兴趣的:(对react的context的研究)