在我看来,通过Context袒露数据可能API不是一种优雅的实践方案,尽量react-redux是这么干的。因此需要一种机制,可能说约束,去低落不须要的影响。
通过childContextTypes和contextTypes这两个静态属性的约束,可以在必然水平保障,只有组件自身,可能是与组件相关的其他子组件才可以随心所欲的会见Context的属性,无论是数据照旧函数。因为只有组件自身可能相关的子组件可以清楚它能会见Context哪些属性,而相对付那些与组件无关的其他组件,无论是内部可能外部的 ,由于不清楚父组件链上各父组件的childContextTypes“声明”了哪些Context属性,所以没法通过contextTypes“申请”相关的属性。所以我领略为,给组件的浸染域Context“带权限”,可以在必然水平上确保Context的可控性和影响范畴。
在开拓组件进程中,我们应该时刻存眷这一点,不要随意的利用Context。
不需要优先利用Context作为React的高级API,React并Context。我的领略是:
Context今朝还处于尝试阶段,大概会在后头的刊行版本中有大的变革,事实上这种环境已经产生了,所觉得了制止给此后进级带来较大影响和贫苦,不发起在App中利用Context。
尽量不发起在App中利用Context,但对付组件而言,由于影响范畴小于App,假如可以做到高内聚,不粉碎组件树的依赖干系,那么照旧可以思量利用Context的。
对付组件之间的数据通信可能状态打点,优先思量用props可能state办理,然后再思量用其他第三方成熟库办理的,以上要领都不是最佳选择的时候,那么再思量利用Context。
Context的更新需要通过setState()触发,可是这并不是靠得住的。Context支持跨组件会见,可是,假如中间的子组件通过一些要领不响应更新,好比shouldComponentUpdate()返回false,那么不能担保Context的更新必然可达利用Context的子组件。因此,Context的靠得住性需要存眷。不外更新的问题,在新版的API中得以办理。
简而言之,只要你能确保Context是可控的,利用Context并无大碍,甚至假如可以或许公道的应用,Context其实可以给React组件开拓带来很强大的体验。
用Context作为共享数据的前言官方所提到Context可以用来举办跨组件的数据通信。而我,把它领略为,比如一座桥,作为一种作为前言举办数据共享。数据共享可以分两类:App级与组件级。
App级的数据共享
App根节点组件提供的Context工具可以当作是App级的全局浸染域,所以,我们操作App根节点组件提供的Context工具建设一些App级的全局数据。现成的例子可以参考react-redux,以下是<Provider />组件源码的焦点实现:
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的根组件用<Provider />组件包裹后,本质上就为App提供了一个全局的属性store,相当于在整个App范畴内,共享store属性。虽然,<Provider />组件也可以包裹在其他组件中,在组件级的全局范畴内共享store。
组件级的数据共享
假如组件的成果不能单靠组件自身来完成,还需要依赖特另外子组件,那么可以操作Context构建一个由多个子组件组合的组件。譬喻,react-router。
react-router的<Router />自身并不能独立完成路由的操纵和打点,因为导航链接和跳转的内容凡是是疏散的,因此还需要依赖<Link />和<Route />等子组件来一同完成路由的相关事情。为了让相关的子组件一同发挥浸染,react-router的实现方案是操作Context在<Router />、<Link />以及<Route />这些相关的组件之间共享一个router,进而完成路由的统一操纵和打点。
下面截取<Router />、<Link />以及<Route />这些相关的组件部门源码,以便更好的领略上述所说的。
// Router.js /** * The public API for putting history on context. */ class Router extends React.Component { static propTypes = { history: PropTypes.object.isRequired, children: PropTypes.node }; static contextTypes = { router: PropTypes.object }; static childContextTypes = { router: PropTypes.object.isRequired }; getChildContext() { return { router: { ...this.context.router, history: this.props.history, route: { location: this.props.history.location, match: this.state.match } } }; } // ...... componentWillMount() { const { children, history } = this.props; // ...... this.unlisten = history.listen(() => { this.setState({ match: this.computeMatch(history.location.pathname) }); }); } // ...... }