什么是事件?
事件是指一些可以通过脚本响应的页面动作。当用户按下鼠标或者提交一个表单等等时候,事件都会出现。事件处理是一段JavaScript代码,总是与页面中的特定部分以及一定的事件相关联。当与页面特定部分相关联的事件发生时,事件处理器就会被调用。
JavaScript常用事件
React的事件处理
React 元素的事件处理和 DOM 元素的很相似。但是React的两点最大的不同是
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
阻止默认行为
注意: 在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault
代码示例:
原生写法:
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
我们返回了false后会阻止<a>
标签的原始跳转功能。只执行我们的console.log
React写法:
function ActionLink() {
function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); }
return (
<a href="#" onClick={handleClick}> Click me
</a>
);
功能上是和上面的代码一样的。但是在这里,e 是一个合成事件。React 根据 W3C 规范来定义这些合成事件,所以你不需要担心跨浏览器的兼容性问题。
为DOM元添加监听器
React不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。只需要在该元素初始渲染的时候添加监听器即可。
代码示例:
定义一个Toggle组件,当我们点击按钮时会切换我们按钮中的值,一直在NO和OFF中切换。
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}
执行我们的切换事件,切换state值
handleClick() {
this.setState(state => ({
进行取反
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
注意: 我们必须谨慎对待 JSX 回调函数中的 this,因为在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined。因为this 本质上就是指向它的调用者,this 是在函数运行时才绑定,在JavaScript 中普通函数都是 window 调用的,所以指向 window但是我们的JSX 语法是不被 webpack 识别的,webpack 默认只能处理 .js 后缀名的文件,所以需要借助 Babel 这个 JavaScript 编译器,而 babel 开启了严格模式 ,开启了严格模式下无法再意外创建全局变量。所以this指向的是 undefined。
解决React组件this指向问题的两种方法
方法一、在构造函数中使用bing
class index extends Component {
constructor(){
super()
this.speak = this.speak.bind(this)
/*解决类中的this问题:this.speak = this.speak.bind(this),构造器里面的this默认指向实例对象,
实例对象通过原型链在类的原型上找着fnc函数,通过bind函数将其this指向改为实例对象,并返回一个新的函数
再将这个新的函数给实例,并取名为fnc*/
}
speak(){
console.log(this)//输出当前实例对象
}
render() {
return (
<div>
<button onClick={this.speak}>按钮</button>
</div>
)
}
}
为什么是bind呢?
众所周知call、apply、bind 都可以改变我们的this指向。那为什么是bind呢?
区别:
- call 和 bind 可以直接接受多个参数 apply 则是将参数放进一个数组
- call 和 apply 返回立即执行函数,bind 返回新的函数,bind()() 也是立即执行
- call和apply都是临时改变一次this指向,并立即执行。而bind是返回一个永久改变this指向的函数。使用 bind 绑定 this 后,该函数里面的 this 不能变化了,不论是谁调用
方法二、将箭头函数赋值给类的属性
class index extends Component {
speak = () =>{
console.log(this)
}
render() {
return (
<div>
<button onClick={this.speak}>按钮</button>
</div>
)
}
}//需要传参的话,可以使用函数柯里化的思想
为什么什么箭头函数没影响呢?
箭头函数:箭头函数并不会创建自己的执行上下文,所以箭头函数中的this都是外层的this,会向外作用域中,一层层查找this,直到有 this 的定义
注意:性能存在差异
使用箭头函数来解决性能会比较低,因为箭头函数不是方法,它们是匿名函数表达式,所以将它们添加到类中的唯一方法是赋值给属性。前面介绍ES6的类的时候可以看出来,ES 类以完全不同的方式处理方法和属性
方法被添加到类的原型中,而不是每个实例定义一次。
类属性语法是为相同的属性分配给每一个实例的语法糖,实际上会在 constructor里面这样实现:
constructor(){
super()
this.speak = () => {console.log(this)}
}
这意味着新实例被创建时,函数就会被重新定义,丢失了JS实例共享原型方法的优势。而方法一,只是在生成实例时多了一步 bind 操作,在效率与内存占用上都有极大的优势
向事件处理程序传递参数
在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
//推荐第二种
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。