Open laizimo opened 7 years ago
react很容易上手,这是真的!!!毕竟对于ES6的知识点熟知度高的话,开发普通的小应用,react不再话下。可是,你是否考虑过,应用中组件间props传递的问题。比方说,我们需要向一个子子子子组件中传递一个props,一层一层的传递是不是过于丑陋了一些呢!那么,你或许会说用redux吧,做一个全局的store管理,这样就不会有这么多的麻烦了。可是,redux本身就不容易上手,何况你的程序可能并没有需要用到它那么复杂。那么,解决办法只有一个——context。这个东西,说实话,并不好用,或许对于不熟悉的你或许会踩坑,那么今天,我们就来好好聊聊它吧。
context是一个尝试性的API,官方也并不建议去使用它。因为它会使得整个程序并不稳定。
首先,我们来尝试一下context的使用。
我们先来模拟一个列表应用,整个列表应用包含、、、
在不使用context的情况下:
class Button extends React.Component { //一个Button组件,返回一个根据颜色定义的按钮 render(){ return ( <button style={{'color' : this.props.color}}> //在button中使用props中的color {this.props.children} </button> ); } } class Message extends React.Component { //在列表的子项目组件,其中包括Button组件 render(){ return ( <div> {this.props.text}<Button color={this.props.color}>Delete</Button> //向Button传递color </div> ); } } class MessageList extends React.Component { //列表组件 render(){ const children = this.props.message.map((item, index) => <Message text={item} color={this.props.color} key={item}/> //向Message传递color ); return ( <div>{children}</div> ); } } class App extends React.Component { //app组件 constructor(props){ super(props); this.state={ message: [ 'hello1', 'hello2' ], color: 'red' }; } render(){ return ( <div> <MessageList message={this.state.message} color={this.state.color}/> //传递state中的color </div> ); } } ReactDOM.render(<App/>, document.getElementById('root'));
源码地址
从这个例子中,我们要聊的是color这个属性。你会发现color一直从App->MessageList->Message->Button,其中一共穿过了2个组件,当然了,这是我们有意为之。但是,我们传递的方式实在是丑陋。
那么,如果我们对之前的进行改写,使用context来直接跨组件传递,或许会好一点。将之前的代码进行修改
// Button部分修改 class Button extends React.Component { render () { return ( <button style={{color: this.context.color}}> //此处直接使用context {this.props.children} </button> ); } } Button.contextTypes = { //增加Button组件中的contextTypes校验 color: PropTypes.String }; //App组件部分修改 class App extends React.Component { constructor(props){ super(props); this.state = { messages: [ 'message1', 'message2' ], color: 'red' }; } getChildContext(){ //增加一个返回context对象的函数getChildContext return {color: 'red'}; } render () { return ( <div> <MessageList messages={this.state.messages}/> </div> ); } } App.childContextTypes = { //这里增加childContextTypes校验 color: PropTypes.String };
其实就是在App中增加了getChildContext()函数,以及childContextTypes和contextTypes两个context的类型校验——这里需要使用到prop-types。我们可以发现,经过这样子的处理,整个传递流程变成了App->Button,中间少了两层组件。整体看上去的风格简洁,有效。
context使用问题
看过上面的测试用例,我们会发现context其实使用起来挺方便的,那么,为何它只作为尝试性API,官方都不推荐使用呢?
因此,我对上述例子进行了一些改动,从这里我们可以看到context的最大的问题。
首先,我们在App组件中增加一个可以改变color值的按钮
class App extends React.Component { //修改后的App constructor(props){ super(props); this.state = { messages: [ 'message1', 'message2' ], color: 'red' }; this.changeColor = this.changeColor.bind(this); } getChildContext(){ return {color: this.state.color}; } changeColor(){ //增加一个函数可以改变state中的color值 this.setState({ color: 'green' }); } render () { return ( <div> <MessageList messages={this.state.messages}/> <button onClick={this.changeColor}>changeColor</button> </div> ); } }
这样我们就可以完成将red转变成green的效果,但是,我们需要去Message组件中添加一个生命周期shouldComponentUpdate,让它的返回值为false,即判断它不更新。
class Message extends React.Component { shouldComponentUpdate(){ return false; } render () { return ( <div> {this.props.text}<Button>Delete</Button> </div> ); } }
这时,你再次点击按钮,你会发现无法改变button的颜色。
原因呢?主要是Message组件处阻断了组件的更新,导致的问题就是虽然context值被修改了,但是更深层次的组件却为更新,这或许是context最大的问题吧。而且context是一个全局的对象,或许存在会污染全局空间,这也是官方不建议使用它的原因。
对于这种深层次的组件状态传递问题,现在的解决办法其实极为有限。
个人觉得,一般组件超过3层以上的传递,就建议使用redux或者redux模拟。因为一般需要传递3层以上组件的,复杂度已经有点大了
Context-React
前言
react很容易上手,这是真的!!!毕竟对于ES6的知识点熟知度高的话,开发普通的小应用,react不再话下。可是,你是否考虑过,应用中组件间props传递的问题。比方说,我们需要向一个子子子子组件中传递一个props,一层一层的传递是不是过于丑陋了一些呢!那么,你或许会说用redux吧,做一个全局的store管理,这样就不会有这么多的麻烦了。可是,redux本身就不容易上手,何况你的程序可能并没有需要用到它那么复杂。那么,解决办法只有一个——context。这个东西,说实话,并不好用,或许对于不熟悉的你或许会踩坑,那么今天,我们就来好好聊聊它吧。
正文
context是一个尝试性的API,官方也并不建议去使用它。因为它会使得整个程序并不稳定。
首先,我们来尝试一下context的使用。
我们先来模拟一个列表应用,整个列表应用包含、、
在不使用context的情况下:
源码地址
从这个例子中,我们要聊的是color这个属性。你会发现color一直从App->MessageList->Message->Button,其中一共穿过了2个组件,当然了,这是我们有意为之。但是,我们传递的方式实在是丑陋。
那么,如果我们对之前的进行改写,使用context来直接跨组件传递,或许会好一点。将之前的代码进行修改
源码地址
其实就是在App中增加了getChildContext()函数,以及childContextTypes和contextTypes两个context的类型校验——这里需要使用到prop-types。我们可以发现,经过这样子的处理,整个传递流程变成了App->Button,中间少了两层组件。整体看上去的风格简洁,有效。
context使用问题
看过上面的测试用例,我们会发现context其实使用起来挺方便的,那么,为何它只作为尝试性API,官方都不推荐使用呢?
因此,我对上述例子进行了一些改动,从这里我们可以看到context的最大的问题。
首先,我们在App组件中增加一个可以改变color值的按钮
这样我们就可以完成将red转变成green的效果,但是,我们需要去Message组件中添加一个生命周期shouldComponentUpdate,让它的返回值为false,即判断它不更新。
源码地址
这时,你再次点击按钮,你会发现无法改变button的颜色。
原因呢?主要是Message组件处阻断了组件的更新,导致的问题就是虽然context值被修改了,但是更深层次的组件却为更新,这或许是context最大的问题吧。而且context是一个全局的对象,或许存在会污染全局空间,这也是官方不建议使用它的原因。
总结
对于这种深层次的组件状态传递问题,现在的解决办法其实极为有限。
个人觉得,一般组件超过3层以上的传递,就建议使用redux或者redux模拟。因为一般需要传递3层以上组件的,复杂度已经有点大了