React-事件处理详解

对于用户界面而言,展示只占整体设计因素的一半,另一半则是相应用户输入,即通过JavaScript处理用户产生的事件。

React通过将事件处理器 绑定到组建上处理事件,事件触发的同时更新组建的内部状态,内部状态更新会触发组件的重绘。因此,如果视图层想要渲染出事件出发后的结果,它所要做的就是渲染函数中读取组件的内部状态。

一、绑定事件处理器

React处理事件本身和原生的JavaScript事件一样:MouseEvents事件用于点击处理器,Change事件用于表单元素变化,等等,所有事件在命名上与原生的JavaScript规范一致,并且会在相同的情境下被触发,React绑定事件处理器的语法和HTML语法非常相似。比如,在我们的问卷制作工具实例中,包含了下面的代码,在Save按钮上 绑定onclick事件处理器。

<button className ='btn btn-save'onClick={this.handleSaveClicked}>Save</button>

 

用户点击这个按钮时,组件的handleSaveClicked方法会被调用。这个方法中包含处理Save行为的逻辑。

 

PS:这个代码可在写法上类似普通不推荐的HTML内联事件处理器属性,比如:onClick,但其实在底层实习那上冰没有使用HTML的onClick属性。React只是用这种写法绑定事件处理器,但内部则是按照需要高效的维护着时间处理器。

如果不用JSX语法,你可以选择在参数对象的属性上指定事件处理器,比如:

React.DOM.button({ClassName:'btnbtn-save',onClick:this.handleSaveClicked},"Save");

其中大部分事件不需要而外的处理就可以工作,但是触控事件需要通过调用一下代码手动启动:

React.initializeTouchEvent(true);

 

二、事件和状态

1、设想你需要让一个组件随着用户的输入而改变,比如在问卷编辑器中,你想要让用户从一个问题类型的菜单当中拖拽问卷问题。

首先,在渲染函数内部基于HTML5拖放(Drag and Drop)API注册事件处理器,代码如下:

var SurveyEdit =React.creatclass({
 

render:function(){
     <div className='survey-edit'>

<div className='row'>

<aside className='sidebar col-md-3'>

<h2>Module</h2>

<DraggableQuestions>

</aside>

<div className='survey-canvas col-md-9'>

    <div

className ={'drop-zone well well-drop-zone'}

onDragOver={this.handleDragOver}

onDragEnter={this.handleDragEnter}

onDragLeave={this.handleDragLeave}

onDrop ={this.handleDrop}

>

Drag and drop a module from the left

</div>

 

</div>

 

</div>

    </div>

},

});

 

三、根据状态进行渲染

事件处理器方法还需要完成一件事——展开当前已经加入的题目清单。为了实现该功能,你需要充分利用每个React组件的内部状态,组件默认是null,但是可以通过它的getInitialState方法将其出事话为合理的值,比如:

getInitaSate:funciton (){

return  {

dropZoneEntered:false,

title:’‘,

introduction:' ',

questions:{}

};

}

以上代码组件初始化了默认值:一个空标题、一个空的介绍、一组空的题目以及一个值为false的dropZoeEntered属性,用于表示当前用户没有拖拽任何内容那个到放置区域。

到这里,你已经可以在render方法当中读取this.state,以便向用户展示当前表单中所有数据了。

 

四、更新状态

更新组件内部状态会出发组件重绘,所以接下来要做的事情就是在拖拽的事件处理器方法中更新状态,然后再次运行render函数,它会从this.state中读取新数据来显示标题,介绍及题目,用户会看到所有内容被正确的更新。

更新组件状态有两种方案:组件的setState方法和repaceState方法。replaceState用一个全新的state对象完整的替换掉原有的state。使用不可变数据结构表示状态时,这种方式很有效,不过很少应用用于其他场景下。更多的情况下回使用setState,它仅仅会把传入的对象合并到已有的state对象。

例如:

getInitialState:funciton(){
      return {

dropZoneEntered:false,

title:'Fantastic Survey',

introduction:'This survey isfantastic!',

question :[]

 

};

}

这时,调用this.setState({title:"Fantasticsurvey 2.0"})仅仅影响this.setState.title的值,而this.state.dropZoneEntered、this.state.introduction及this.state.questions不会受影响。

而如果调用this.replaceState({title:"FantasticSurvey 2.0"}),则会用新的对象{title:“Fantastic Survey 2.0}替换掉整个state对象,同时把this.state.dropZone-Entered]this.state.introduction和this.state.questions全部清除掉。这样做很可能中断render函数执行,因为它期望this.state.questions是一个数组而不是undefined。现在使用this.setState可以实现上文中提到事件处理器方法。

使用this.State可以实现上文提到的事件处理器方法。

handleFormChange:function(formData){

this.setSate(formData);

}.

handleDragOver:function(ev){

//这保证 handleDroZoneDrop可以被调用

ev.preventDefault();

},

handleDragEnter:function(){

this.setState({dropZoneEntered:true});

},

handleDragLeave:function(){

this.setState({dropZoneEntered:false});

},

handleDrop:function(ev){

var questionType =ev.dataTransfer.getData('questionType');

var questions =this.state.questions;

questions = questions.concat({type:questionType});

this.setState({

questions:questions,

dropZoneEntered:false

});

});

 这一点很重要永远不要尝试通过setState或者replaceState以外的方法去修改state对象,类似this.state.saveInProgress =true通常不是一个好主意,因为它无法通知React师傅需要重新渲染组件,而且可能回答熬制下次调用setState时出现意外结果。

 

五、事件对象

很多事件处理器只要触发就会完成功能,但有时也会需要关于用户输入的更多信息。例如:

var AnswerEssayQuestion=React.createClass({

handleComplete:functin(event){

this.callMethodOnProps('onCompleted',event.target.value);

},

},

render:function(){
           return(

<div className="form-group">

<lavel className="survey-item-label">{this.props.label}</label>

<div className="survey-item-content">

<textarea className="form-control" rows="3"onBlur={this.handleComplete}/>

</div>

</div>

);

}

通常会有一个事件对象传入到React的事件处理函数中,类似于原生的JavaScript事件监听器的写法。这里的handleComplete方法会接受一个事件对象,并通过存取event.target.value值为textarea赋值,在事件处理器中,使用event.target.value获取表单中input值是一个常规的方法,尤其在onClange事件处理器中。

注意:callMethodOnProps是由一个叫做PropsMethodMixin的mixin提供的,此外这个mixin还提供了一些处理父组件之间通信的简便办法。

 

React把原生的事件封装在一个SyntheticEvent实例中,而不是直接把原生的浏览器事件传给处理器,SyntheticEvent在表现和功能上都与浏览器的原生事件一致,而且消除了跨浏览器差异。

对于用户界面而言,展示只占整体设计因素的一半,另一半则是相应用户输入,即通过JavaScript处理用户产生的事件。

React通过将事件处理器 绑定到组建上处理事件,事件触发的同时更新组建的内部状态,内部状态更新会触发组件的重绘。因此,如果视图层想要渲染出事件出发后的结果,它所要做的就是渲染函数中读取组件的内部状态。

一、绑定事件处理器

React处理事件本身和原生的JavaScript事件一样:MouseEvents事件用于点击处理器,Change事件用于表单元素变化,等等,所有事件在命名上与原生的JavaScript规范一致,并且会在相同的情境下被触发,React绑定事件处理器的语法和HTML语法非常相似。比如,在我们的问卷制作工具实例中,包含了下面的代码,在Save按钮上 绑定onclick事件处理器。

<button className ='btn btn-save'onClick={this.handleSaveClicked}>Save</button>

 

用户点击这个按钮时,组件的handleSaveClicked方法会被调用。这个方法中包含处理Save行为的逻辑。

 

PS:这个代码可在写法上类似普通不推荐的HTML内联事件处理器属性,比如:onClick,但其实在底层实习那上冰没有使用HTML的onClick属性。React只是用这种写法绑定事件处理器,但内部则是按照需要高效的维护着时间处理器。

如果不用JSX语法,你可以选择在参数对象的属性上指定事件处理器,比如:

React.DOM.button({ClassName:'btnbtn-save',onClick:this.handleSaveClicked},"Save");

其中大部分事件不需要而外的处理就可以工作,但是触控事件需要通过调用一下代码手动启动:

React.initializeTouchEvent(true);

 

二、事件和状态

1、设想你需要让一个组件随着用户的输入而改变,比如在问卷编辑器中,你想要让用户从一个问题类型的菜单当中拖拽问卷问题。

首先,在渲染函数内部基于HTML5拖放(Drag and Drop)API注册事件处理器,代码如下:

var SurveyEdit =React.creatclass({
 

render:function(){
     <div className='survey-edit'>

<div className='row'>

<aside className='sidebar col-md-3'>

<h2>Module</h2>

<DraggableQuestions>

</aside>

<div className='survey-canvas col-md-9'>

    <div

className ={'drop-zone well well-drop-zone'}

onDragOver={this.handleDragOver}

onDragEnter={this.handleDragEnter}

onDragLeave={this.handleDragLeave}

onDrop ={this.handleDrop}

>

Drag and drop a module from the left

</div>

 

</div>

 

</div>

    </div>

},

});

 

三、根据状态进行渲染

事件处理器方法还需要完成一件事——展开当前已经加入的题目清单。为了实现该功能,你需要充分利用每个React组件的内部状态,组件默认是null,但是可以通过它的getInitialState方法将其出事话为合理的值,比如:

getInitaSate:funciton (){

return  {

dropZoneEntered:false,

title:’‘,

introduction:' ',

questions:{}

};

}

以上代码组件初始化了默认值:一个空标题、一个空的介绍、一组空的题目以及一个值为false的dropZoeEntered属性,用于表示当前用户没有拖拽任何内容那个到放置区域。

到这里,你已经可以在render方法当中读取this.state,以便向用户展示当前表单中所有数据了。

 

四、更新状态

更新组件内部状态会出发组件重绘,所以接下来要做的事情就是在拖拽的事件处理器方法中更新状态,然后再次运行render函数,它会从this.state中读取新数据来显示标题,介绍及题目,用户会看到所有内容被正确的更新。

更新组件状态有两种方案:组件的setState方法和repaceState方法。replaceState用一个全新的state对象完整的替换掉原有的state。使用不可变数据结构表示状态时,这种方式很有效,不过很少应用用于其他场景下。更多的情况下回使用setState,它仅仅会把传入的对象合并到已有的state对象。

例如:

getInitialState:funciton(){
      return {

dropZoneEntered:false,

title:'Fantastic Survey',

introduction:'This survey isfantastic!',

question :[]

 

};

}

这时,调用this.setState({title:"Fantasticsurvey 2.0"})仅仅影响this.setState.title的值,而this.state.dropZoneEntered、this.state.introduction及this.state.questions不会受影响。

而如果调用this.replaceState({title:"FantasticSurvey 2.0"}),则会用新的对象{title:“Fantastic Survey 2.0}替换掉整个state对象,同时把this.state.dropZone-Entered]this.state.introduction和this.state.questions全部清除掉。这样做很可能中断render函数执行,因为它期望this.state.questions是一个数组而不是undefined。现在使用this.setState可以实现上文中提到事件处理器方法。

使用this.State可以实现上文提到的事件处理器方法。

handleFormChange:function(formData){

this.setSate(formData);

}.

handleDragOver:function(ev){

//这保证 handleDroZoneDrop可以被调用

ev.preventDefault();

},

handleDragEnter:function(){

this.setState({dropZoneEntered:true});

},

handleDragLeave:function(){

this.setState({dropZoneEntered:false});

},

handleDrop:function(ev){

var questionType =ev.dataTransfer.getData('questionType');

var questions =this.state.questions;

questions = questions.concat({type:questionType});

this.setState({

questions:questions,

dropZoneEntered:false

});

});

 这一点很重要永远不要尝试通过setState或者replaceState以外的方法去修改state对象,类似this.state.saveInProgress =true通常不是一个好主意,因为它无法通知React师傅需要重新渲染组件,而且可能回答熬制下次调用setState时出现意外结果。

 

五、事件对象

很多事件处理器只要触发就会完成功能,但有时也会需要关于用户输入的更多信息。例如:

var AnswerEssayQuestion=React.createClass({

handleComplete:functin(event){

this.callMethodOnProps('onCompleted',event.target.value);

},

},

render:function(){
           return(

<div className="form-group">

<lavel className="survey-item-label">{this.props.label}</label>

<div className="survey-item-content">

<textarea className="form-control" rows="3"onBlur={this.handleComplete}/>

</div>

</div>

);

}

通常会有一个事件对象传入到React的事件处理函数中,类似于原生的JavaScript事件监听器的写法。这里的handleComplete方法会接受一个事件对象,并通过存取event.target.value值为textarea赋值,在事件处理器中,使用event.target.value获取表单中input值是一个常规的方法,尤其在onClange事件处理器中。

注意:callMethodOnProps是由一个叫做PropsMethodMixin的mixin提供的,此外这个mixin还提供了一些处理父组件之间通信的简便办法。

 

React把原生的事件封装在一个SyntheticEvent实例中,而不是直接把原生的浏览器事件传给处理器,SyntheticEvent在表现和功能上都与浏览器的原生事件一致,而且消除了跨浏览器差异。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值