react 实现数据双向绑定

首先从没有使用mixin的例子引入

 

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. var BindingExample = React.createClass({  
  2.             getInitialState: function() {  
  3.                 return {  
  4.                     text: ''  
  5.                 }  
  6.             },  
  7.             handleChange: function(event) {  
  8.                 this.setState({text: event.target.value})  
  9.             },  
  10.             render: function() {  
  11.                 return <div>  
  12.                     <input type="text" placeholder="请输入内容" onChange={this.handleChange} />  
  13.                     <p>{this.state.text}</p>  
  14.                 </div>  
  15.             }  
  16.         })  
  17. React.render(<BindingExample></BindingExample>, document.body);  

 

 

这个例子大家都很熟悉,当input框发生改变的时候,去调用handleChange方法,然后通过setState重新render P标签中的数据

 

接下来引入使用mixin的一个例子,没有使用官方的方法

 

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. var BindingChange= {  
  2.   
  3.             handleChange: function(key) {  
  4.   
  5.                 var that = this,  
  6.                     newState = {};  
  7.   
  8.                 return function(e) {  
  9.   
  10.                     newState[key] = e.target.value;  
  11.                     that.setState(newState);  
  12.   
  13.                 }  
  14.   
  15.             }  
  16.   
  17.         }  
  18.   
  19.         var BindingExample1 = React.createClass({  
  20.   
  21.             mixins: [BindingChange],  
  22.   
  23.             getInitialState: function() {  
  24.                 return {  
  25.                     text: "",  
  26.                     comment: ""  
  27.                 }  
  28.             },  
  29.             render: function() {  
  30.                 return (  
  31.                     <div>  
  32.                          <input type="text" placeholder="请输入内容" onChange={this.handleChange('text').bind(this)} />  
  33.                                  <textarea onChange={this.handleChange('comment').bind(this)}></textarea>  
  34.                                      <p>{this.state.text}</p>  
  35.                                      <p>{this.state.comment}</p>  
  36.                     </div>  
  37.                 );  
  38.             }  
  39.   
  40.         })  
  41.         React.render(<BindingExample1 />,document.body);  


来分析一下这个例子

 

首先看BindingExample中的render,仔细观察一下实际上和例子一没有什么区别,只是在onChange处理的函数上绑定了上下文,还在在函数里面传了一个值(key)

这个key和state中对应的key值要相同,如例子中input改变的时候是修改state中的"text"这个状态,所以传入"text"。

然后再看BindingExample中的mixins,把BindingChange引用了进来,在引用之后,BindingChange中的东西就会变成BindingExample的东西

所以onChange那里进行bind之后,BindingChange的this指针指向了BindingExample,而不是window。

 

接着看一下BindingChange。先定义了一个that来保存当前的this,接下里定义了一个对象

为什么要定义一个对象呢。

可以发现,React中setState要修改的状态名字不是一个字符串,也不能解析变量。如果假如onChange事件中传入的key为"text",直接这样修改 setState({key:event.target.value}) 实际上并没有修改text的值,然是去修改了key的值,然而我们并没有在实际的代码中存在key这个状态,所以并不会发生改变。

所以在return的那个函数中newState[key] = e.target.value,这个时候key就可以解析成了text,并且进行了赋值,然后将该对象传入setState中,text这个状态得以改变。

当然,假如传入的是comment这个值,那么这个key实际上就是comment,然后改变的是comment的状态

 

读到这里大家可能都发现了,mixin做的就是把一些相同的东西抽离出来,就像这个onChange事件,如果没用mixin的话,可能就要写onChange1和onChange2。实际上就像方法的封装一下。当然也有不好的地方,就是查找这个方法的时候可能不会一下子找到。

 

最后引入官方的例子

 

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. var BindingExample2 = React.createClass({  
  2.     mixins: [React.addons.LinkedStateMixin],  
  3.     getInitialState: function() {  
  4.         return {  
  5.             text: "",  
  6.             comment: ""  
  7.         }  
  8.     },  
  9.     render: function() {  
  10.         return (  
  11.             <div>  
  12.                 <input type="text" placeholder="请输入内容" valueLink={this.linkState('text')} />  
  13.                                  <textarea valueLink={this.linkState('comment')}></textarea>  
  14.                                  <p>{this.state.text}</p>  
  15.                                  <p>{this.state.comment}</p>  
  16.             </div>  
  17.         );  
  18.     }  
  19.  });  
  20.  React.render(<BindingExample2 />,document.body);  

对比例子2,我们发现在mixin中使用了React.addons.LinkedStateMixin,这个就是官方封装好的自己的双向绑定的方法

 

再往下读下去发现onChange事件变成了valueLink,然后使用了方法linkState,而传入的值依旧是这个input想要改变的状态的名字。

 

我们来看一下官方的这个方法是怎么封装的

 

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. var ReactLink = _dereq_(75);  
  2.      var ReactStateSetters = _dereq_(94);  
  3.   
  4.      var LinkedStateMixin = {  
  5.          linkState: function(key) {  
  6.              return new ReactLink(  
  7.                  this.state[key],  
  8.                  ReactStateSetters.createStateKeySetter(this, key)  
  9.              );  
  10.          }  
  11.      };  
  12.   
  13.      module.exports = LinkedStateMixin;  

这个就是方法封装的mixin的LinkedStateMixin方法

 

官方是这么解释的

ReactLink encapsulates a common pattern in which a component wants to modify a prop received from its parent.

ReactLink封装了一个需要从父级获取值并且修改的一个公有的模式。(实际上就是绑定上下文环境,然后函数的封装)

 

然后我们去查看ReactStateSetters.createStateKeySetter这个方法是这样写的

 

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. createStateKeySetter: function(component, key) {  
  2.   // Memoize the setters.  
  3.   var cache = component.__keySetters || (component.__keySetters = {});  
  4.   return cache[key] || (cache[key] = createStateKeySetter(component, key));  
  5. }  

传入上下文环境,传入要修改的状态的名字。看到cache,大家也能明白这是缓存的意思,判断是否有这个状态,有的话直接复制,并返回。没有的话就创建一个对象,然后进入(cache[key] = createStateKeySetter(component, key))这个方法中

 

 

然后继续找到了createStateKeySetter,他是这个样子的

 

[javascript] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. function createStateKeySetter(component, key) {  
  2.   var partialState = {};  
  3.   return function stateKeySetter(value) {  
  4.     partialState[key] = value;  
  5.     component.setState(partialState);  
  6.   };  
  7. }  

继续传入上下文环境,传入要修改的状态的名字。然后往下读,是不是突然发现很熟悉,这个不就是和例子二中的handleChange是一模一样的。

 

 

此篇博文到此就结束了。

 

posted @ 2016-09-29 15:31  xiezhenzhong  阅读(730)  评论(0编辑  收藏  举报