React是怎么进行事件处理的

什么是事件?

事件是指一些可以通过脚本响应的页面动作。当用户按下鼠标或者提交一个表单等等时候,事件都会出现。事件处理是一段JavaScript代码,总是与页面中的特定部分以及一定的事件相关联。当与页面特定部分相关联的事件发生时,事件处理器就会被调用。

JavaScript常用事件

React的事件处理

React 元素的事件处理和 DOM 元素的很相似。但是React的两点最大的不同是

  1. React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  2. 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

阻止默认行为

注意: 在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault

代码示例:

原生写法:

js 复制代码
<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

我们返回了false后会阻止<a>标签的原始跳转功能。只执行我们的console.log

React写法:

js 复制代码
    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 元素添加监听器。只需要在该元素初始渲染的时候添加监听器即可。

代码示例:

js 复制代码
    定义一个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

js 复制代码
    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 不能变化了,不论是谁调用

方法二、将箭头函数赋值给类的属性

js 复制代码
    class index extends Component { 
        speak = () =>{ 
            console.log(this)
     } 
         render() { 
             return ( 
                 <div> 
                 <button onClick={this.speak}>按钮</button> 
                 </div> 
               ) 
          }
     }//需要传参的话,可以使用函数柯里化的思想

为什么什么箭头函数没影响呢?

箭头函数:箭头函数并不会创建自己的执行上下文,所以箭头函数中的this都是外层的this,会向外作用域中,一层层查找this,直到有 this 的定义

注意:性能存在差异

使用箭头函数来解决性能会比较低,因为箭头函数不是方法,它们是匿名函数表达式,所以将它们添加到类中的唯一方法是赋值给属性。前面介绍ES6的类的时候可以看出来,ES 类以完全不同的方式处理方法和属性

方法被添加到类的原型中,而不是每个实例定义一次。

类属性语法是为相同的属性分配给每一个实例的语法糖,实际上会在 constructor里面这样实现:

js 复制代码
    constructor(){
        super()
        this.speak = () => {console.log(this)}
    }

这意味着新实例被创建时,函数就会被重新定义,丢失了JS实例共享原型方法的优势。而方法一,只是在生成实例时多了一步 bind 操作,在效率与内存占用上都有极大的优势

向事件处理程序传递参数

在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

js 复制代码
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    //推荐第二种
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

相关推荐
前端组件开发1 小时前
基于uni-app与图鸟UI的移动应用模板构建研究
java·开发语言·前端·ui·小程序·前端框架·uni-app
橙子味冰可乐2 小时前
isprintable()方法——判断字符是否为可打印字符
java·前端·javascript·数据库·python
yunpeng.zhou2 小时前
logging 模块简单使用记录
java·前端·数据库
奋斗吧程序媛4 小时前
使用vue动态给同一个a标签添加内容 并给a标签设置hover,悬浮文字变色,结果鼠标悬浮有的字上面不变色
前端·javascript·vue.js
王天平·Jason Wong6 小时前
vue3弹窗usehook
前端·javascript·vue.js
小跳不会Coding6 小时前
vue开发网站--关于window.print()调取打印
前端·javascript·vue.js
concisedistinct7 小时前
深入浅出:npm常用命令详解与实践
前端·npm·node.js·工具·modules
Lily.C7 小时前
【JavaScript 小工具】——获取富文本中的`<a>`标签 中的href值以及a标签中的内容
开发语言·javascript
碎像8 小时前
使用AI工具 Baidu Comate 辅助编码 快速定位修改Bug
java·前端·后端·bug·intellij idea
snow@li8 小时前
工程化:Commitlint / 规范化Git提交消息格式
前端·git