React.js的context
这一节的内容其实是讲一个react当中一个你可能永远用不到的特性——context,但是它对你理解react-redux很有好处。那么context是干什么的呢?看下图:
假设现在这个组件树代表的应用是用户可以自主换主题色的,每个子组件会根据主题色的不同调整自己的字体颜色。“主题色”这个状态是所有组件共享的状态,根据状态提升中所提到的,需要把这个状态提升到根节点的 Index 上,然后把这个状态通过 props 一层层传递下去:
如果要改变主题色,在 Index 上可以直接通过 this.setState({ themeColor: ‘red’ }) 来进行。这样整颗组件树就会重新渲染,子组件也就可以根据重新传进来的 props.themeColor 来调整自己的颜色。
但这里的问题也是非常明显的,我们需要把 themeColor 这个状态一层层手动地从组件树顶层往下传,每层都需要写 props.themeColor。如果我们的组件树很层次很深的话,这样维护起来简直是灾难。
如果这颗组件树能够全局共享这个状态就好了,我们要的时候就去取这个状态,不用手动地传:
就像这样,Index 把 state.themeColor 放到某个地方,这个地方是每个 Index 的子组件都可以访问到的。当某个子组件需要的时候就直接去那个地方拿就好了,而不需要一层层地通过 props 来获取。不管组件树的层次有多深,任何一个组件都可以直接到这个公共的地方提取 themeColor 状态。
React.js 的 context 就是这么一个东西,某个组件只要往自己的 context 里面放了某些状态,这个组件之下的所有子组件都直接访问这个状态而不需要通过中间组件的传递。一个组件的 context 只有它的子组件能够访问。
下面我们看看 React.js 的 context 代码怎么写,我们先把整体的组件树搭建起来。
用create-react-app创建工程:
create-react-app react-context-demo
现在我们修改 App,让它往自己的 context 里面放一个 themeColor:app.js
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import logo from './logo.svg'; import './App.css'; import Title from './title' class App extends Component { static childContextTypes = { themeColor: PropTypes.string } constructor() { super() this.state = { themeColor: 'red' } } getChildContext() { return { themeColor : this.state.themeColor } } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <Title /> </header> <p className="App-intro"> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); } } export default App;
构造函数里面的内容其实就很好理解,就是往 state 里面初始化一个 themeColor 状态。getChildContext 这个方法就是设置 context 的过程,它返回的对象就是 context(也就是上图中处于中间的方块),所有的子组件都可以访问到这个对象。我们用 this.state.themeColor 来设置了 context 里面的 themeColor。
接下来我们要看看子组件怎么获取这个状态,修改 App 的孙子组件 Title:title.js
import React, { Component } from 'react'; import PropTypes from 'prop-types'; export default class Title extends Component { static contextTypes = { themeColor: PropTypes.string } render() { return (<h1 style={{ color: this.context.themeColor }}>我是标题</h1>); } }
一个组件可以通过 getChildContext 方法返回一个对象,这个对象就是子树的 context,提供 context 的组件必须提供 childContextTypes 作为 context 的声明和验证。
如果一个组件设置了 context,那么它的子组件都可以直接访问到里面的内容,它就像这个组件为根的子树的全局变量。任意深度的子组件都可以通过 contextTypes 来声明你想要的 context 里面的哪些状态,然后可以通过 this.context 访问到那些状态。
context 打破了组件和组件之间通过 props 传递数据的规范,极大地增强了组件之间的耦合性。而且,就如全局变量一样,context 里面的数据能被随意接触就能被随意修改,每个组件都能够改 context 里面的内容会导致程序的运行不可预料。
所以会再下一章讲解关于redux的相关知识点。
评论前必须登录