React.js 的 context 就是这么一个东西,某个组件只要往自己的 context 里面放了某些状态,这个组件之下的所有子组件都直接访问这个状态而不需要通过中间组件的传递。一个组件的 context 只有它的子组件能够访问,它的父组件是不能访问到的,你可以理解每个组件的 context 就是瀑布的源头,只能往下流不能往上飞
classIndexextendsComponent{
staticchildContextTypes={
themeColor:PropTypes.string
}
constructor() {
super()
this.state={themeColor:'red'}
}
getChildContext() {
return{themeColor:this.state.themeColor}
}
render() {
return(
)
}
}
构造函数里面的内容其实就很好理解,就是往 state 里面初始化一个 themeColor 状态。getChildContext 这个方法就是设置 context 的过程,它返回的对象就是 context(也就是上图中处于中间的方块),所有的子组件都可以访问到这个对象。我们用 this.state.themeColor 来设置了 context 里面的 themeColor。
还有一个看起来很可怕的 childContextTypes,它的作用其实 propsType 验证组件 props 参数的作用类似。不过它是验证 getChildContext 返回的对象。为什么要验证 context,因为 context 是一个危险的特性,按照 React.js 团队的想法就是,把危险的事情搞复杂一些,提高使用门槛人们就不会去用了。如果你要给组件设置 context,那么 childContextTypes 是必写的。
现在我们已经完成了 Index 往 context 里面放置状态的工作了,接下来我们要看看子组件怎么获取这个状态,修改 Index 的孙子组件 Title:
classTitleextendsComponent{
staticcontextTypes={
themeColor:PropTypes.string
}
render() {
return(
)
}
}
子组件要获取 context 里面的内容的话,就必须写 contextTypes 来声明和验证你需要获取的状态的类型,它也是必写的,如果你不写就无法获取 context 里面的状态。Title 想获取 themeColor,它是一个字符串,我们就在 contextTypes 里面进行声明。
一个组件可以通过 getChildContext 方法返回一个对象,这个对象就是子树的 context,提供 context 的组件必须提供 childContextTypes 作为 context 的声明和验证。
总结:
一个组件可以通过 getChildContext 方法返回一个对象,这个对象就是子树的 context,提供 context 的组件必须提供 childContextTypes 作为 context 的声明和验证
如果一个组件设置了 context,那么它的子组件都可以直接访问到里面的内容,它就像这个组件为根的子树的全局变量。任意深度的子组件都可以通过 contextTypes 来声明你想要的 context 里面的哪些状态,然后可以通过 this.context 访问到那些状态。
context 打破了组件和组件之间通过 props 传递数据的规范,极大地增强了组件之间的耦合性。而且,就如全局变量一样,context 里面的数据能被随意接触就能被随意修改,每个组件都能够改 context 里面的内容会导致程序的运行不可预料。
但是这种机制对于前端应用状态管理来说是很有帮助的,因为毕竟很多状态都会在组件之间进行共享,context 会给我们带来很大的方便。一些第三方的前端应用状态管理的库(例如 Redux)就是充分地利用了这种机制给我们提供便利的状态管理服务。但我们一般不需要手动写 context,也不要用它,只需要用好这些第三方的应用状态管理库就行了。
React-redux
React.js 除了状态提升以外并没有更好的办法帮我们解决组件之间共享状态的问题,而使用 context 全局变量让程序不可预测。 store 里面的内容是不可以随意修改的,而是通过 dispatch 才能变更里面的 state。所以我们尝试把 store 和 context 结合起来使用,可以兼顾组件之间共享状态问题和共享状态可能被任意修改的问题。
store 和 context 结合有诸多缺陷,有大量的重复逻辑和对 context 的依赖性过强。我们尝试通过构建一个高阶组件 connect 函数的方式,把所有的重复逻辑和对 context 的依赖放在里面 connect 函数里面,而其他组件保持 Pure(Dumb) 的状态,让 connect 跟 context 打交道,然后通过 props 把参数传给普通的组件。
而每个组件需要的数据和需要触发的 action 都不一样,所以调整 connect,让它可以接受两个参数 mapStateToProps 和 mapDispatchToProps,分别用于告诉 connect这个组件需要什么数据和需要触发什么 action。
最后为了把所有关于 context 的代码完全从业务逻辑里面清除掉,构建了一个 Provider 组件。Provider 作为所有组件树的根节点,也就是容器组件。外界可以通过 props 给它提供 store,它会把 store 放到自己的 context 里面,好让子组件 connect 的时候都能够获取到。
react-redux两个内容:connect 函数(高阶组件)和 Provider 容器组件