frontend-interview icon indicating copy to clipboard operation
frontend-interview copied to clipboard

Day19 - React中的事件绑定与箭头函数

Open su37josephxia opened this issue 3 years ago • 27 comments

React 事件绑定有好几种方式,我快懵了 https://juejin.cn/post/6844903861011005448 [译] 为什么需要在 React 类组件中为事件处理程序绑定 this https://juejin.cn/post/6844903605984559118

su37josephxia avatar Jan 18 '22 11:01 su37josephxia

问题有错别字,事件绑定

bianzheCN avatar Jan 18 '22 11:01 bianzheCN

React的事件绑定将处理程序作为回调传递,当事件被触发并且处理程序被调用时,this的值会回退到默认绑定,即值为 undefined,这是因为类声明和原型方法是以严格模式运行。

在箭头函数的情况下,this 是有词法约束力的。这意味它可以使用封闭的函数上下文或者全局上下文作为 this 的值。

在箭头函数作为回调的例子中,箭头函数被包含在 render() 方法中,该方法由 React 在组件实例的上下文中调用。这就是为什么箭头函数也可以捕获相同的上下文,并且其中的 this 值将正确的指向组件实例。

qytayh avatar Jan 19 '22 12:01 qytayh

React的绑定到dom上的事件,若不是箭头函数,则由于异步调用的原因,且事件被封装了一层,又由于 class 中代码都是以strict 模式运行,所以this会指向 undefined。

若是箭头函数,由于其没有this则 向上溯源this,而我们明确的在Class内定义的,所以this为 组件实例本身。

BambooSword avatar Jan 19 '22 13:01 BambooSword

jsx语法中,是类似于传参的方式,直接插入到模板中的感觉。所以假如绑定个onclick事件,就通过传入 this.handleClick,实现事件绑定。但是这种方法就有点类似于 let fn = obj.fn, 然后调用 fn。就会出现函数丢失上下文环境,如果在浏览器写这样的代码,this会指向window。而在 react 中会指向 undefined,这有种像 use strict 严格模式的感觉。我猜测 react 是想实现一个严格模式,保证函数执行的上下文环境是不变的,和 react 讲纯函数一样,喜欢不变的东西。如果没有显式的指明 this,就会绑上 undefined。而 react 解决这样的问题是通过bind绑定或者用箭头函数,这些操作都是指明this,然后不让this被更改的操作。

zcma11 avatar Jan 19 '22 13:01 zcma11

react的事件绑定将处理函数作为回调传递后,丢失了上下文,导致this值变为undefined,此时this绑定是默认绑定,而在箭头函数情况下,this指向当前所在的上下文,在react中将箭头函数作为回调,就不存在问题了

QbjGKNick avatar Jan 19 '22 13:01 QbjGKNick

React在构建虚拟DOM的同时,还构建了自己的事件系统;且所有事件对象和W3C规范保持一致。React的事件系统和浏览器事件系统相比,主要增加了两个特性:事件代理、和事件自动绑定

  • 事件自动绑定
    • 在JavaScript中创建回调函数时,一般要将方法绑定到特定的实例,以保证this的正确性;
    • 在React中,每个事件处理回调函数都会自动绑定到组件实例(使用ES6语法创建的例外);
    • 注意:事件的回调函数被绑定在React组件上,而不是原始的元素上,即事件回调函数中的this所指的是组件实例而不是DOM元素
  • 箭头函数
    • 正常情况下tihs都指向window,而react里面只能指向组件实例不能指向window,当this向发生改变不指向组件时指向就会丢失就成了未定义

    • 我们知道jsx的原理本质上是React.createElement(),而React.createElement()有三个参数

      • 第一个参数html标签的名字
      • 第二个参数是传入的标签属性 传入的属性是以键值对的格式传入
      • 第三个属性是节点要显示的内容
      • 所以在第二个参数传入标签属性的时候,这时this就丢失了
    • 解决办法

      • function() {} this.function.bind(this)
      • function = () => {} this.function

zzzz-bang avatar Jan 19 '22 13:01 zzzz-bang

分析两个问题

  • react中为什么需要用bind给腹痛函数事件绑定this
  • 为什么事件函数用箭头函数就不需要为箭头函数绑定this

问题一

这个不是react决定的,而是由js语言特性决定的。因为由js的this绑定规则可以知道,函数的this会因为赋值,或者函数作为参数传递(隐式赋值),丢失this绑定。
react也是如此,由于将处理程序作为回调传递后,丢失了上下文,导致 this 值变成 undefined(因为类声明和类表达式的主体以 严格模式 执行)。

class Foo {
  constructor(name){
    this.name = name
    this.display = this.display.bind(this);
  }

  display(){
    console.log(this.name);
  }
}

var foo = new Foo('Saurabh');
foo.display(); // Saurabh

var display = foo.display;
display(); // Saurabh

所以为了避免错误,我们需要像下文这样绑定 this 的值,bind执行硬绑定,函数中的this就不会再被隐式修改了。

问题二,箭头函数

class Foo extends React.Component{
  handleClick = () => {
    console.log(this); 
  }
 
  render(){
    return (
      <button type="button" onClick={this.handleClick}>
        Click Me
      </button>
    );
  }
}

ReactDOM.render(
  <Foo />,
  document.getElementById("app")
);

因为箭头函数没有自己的this,aguments等,是用的非箭头父函数的this。

上述例子中,箭头函数被包含在 Foo 类中或者构造函数中,所以它的上下文就是组件实例,而这就是我们想要的。箭头函数中可以直接用this访问组件实例。

JanusJiang1 avatar Jan 19 '22 14:01 JanusJiang1

react中绑定事件,如果定义的方法用的是普通函数那么需要手动bind 绑定this值,否则this会变成undefined,但是如果用的是箭头函数的话就不需要了。 箭头函数可以是因为,箭头函数没有自己的this,其this保留的是定义这个箭头函数所在的上下文,所以说使用箭头函数时,它会自动绑定到当前组件示例 而普通函数是谁调用就指向谁,react将绑定的当前事件传递给正式的函数处理运行,在这过程中丢失了上下文,又因为class声明的代码中使用的是严格模式所以this会是undefined;

Limeijuan avatar Jan 19 '22 14:01 Limeijuan

react的事件绑定是使用回调函数的方式来调用的,又因为class中是以严格模式运行的,所以当调用时会丢失this,所以在类组件中定义事件函数时要使用箭头函数,或者直接使用bind绑定this

yaoqq632319345 avatar Jan 19 '22 14:01 yaoqq632319345

react为什么需要事件绑定

  • 当我们在react中将事件函数作为回调传递后,该函数是一个纯调用函数,而类声明和类表达式的主体以 严格模式 执行,所以会丢失this的指向,变为undefined,所以我们需要显示绑定函数的this指针指向当前构造函数或者类的实例函数

为何使用箭头函数

  • 箭头函数自己并没有this指针,而是引用上级作用域的上下文,在react的jsx语法中,箭头函数的上级作用域一般就是当前类实例或者构造函数

aiuluna avatar Jan 19 '22 14:01 aiuluna

React组件类中,使用了ES6的Class定义了一个组件类,当在其他组件中调用或者使用ReactDOM.render()方法将其渲染到界面时会生成一个组件实例。根据this指向的基本规则,这里的this最终会指向组件的实例。组件实例生成的时候,构造器constructor会被执行this.handleClick = this.handleClick.bind(this) 而Class的内部是强制运行在严格模式下的,不会指定this为window,而是undefined。因此,如果不进行this.handleClick = this.handleClick.bind(this);的话,handleClick方法执行时,内部的this为undefined,如若访问this的属性就会报错。

674252256 avatar Jan 19 '22 14:01 674252256

react中的事件绑定(Event handlers)需要是通过在render中绑定this,或者handlers中绑定this来实现一些当前类的方法来进行处理,即类方法并不是默认绑定的,原因是因为在实际源码的处理中,我们实现的Event handlers是通过 handler()的方式调用的,并不是通过 class.halder()的方式在调用,因此需要强制在render中或者handler中改变一下this指向为当前类。

箭头函数在定义的过程中则不需要bind,因为箭头函数没有自己的this等参数,一旦被创建,则this已经被确定,因此箭头函数不需要强制事件绑定。

MMmaXingXing avatar Jan 19 '22 14:01 MMmaXingXing

  • 在js中,函数的this会因为赋值,或者函数作为参数传递,丢失this绑定。

`let obj = {

name:'obj',

func:function test(react) {

//this.func = this.func.bind(this);

console.log(react)

console.log(this);

}

}

obj.func('sdf');

let aaa = obj.func;

aaa('sdf');`

不加注释行,obj.func('sdf')的this输出obj对象,而aaa('sdf')的this丢失了,加上注释行后,aaa('sdf')的this也是指向了obj这个对象。

  • 所以在react中事件绑定是使用回调函数的方式来调用的,this会丢失,而使用箭头函数,因为箭头函数本身没有this,其this指向的永远是他的父级,所以我们在构造实例的时候使用箭头函数,他的this指向就会指向实例本身。

wzl624 avatar Jan 19 '22 15:01 wzl624

在js中,函数的this会因为赋值,或者函数作为参数传递,丢失this绑定。

解决方法 1.使用箭头函数:由于箭头函数的特性在箭头函数内的this即是指向当前对象的上下问 所以使用箭头函数可以解决 2. 使用在绑定事件时使用bind(this)改变this指向 3.在constructor里使用bind()来改变事件对象的this指向

partiallove avatar Jan 19 '22 15:01 partiallove

React的事件绑定将处理程序作为回调传递,函数作为参数传递(隐式赋值),丢失this绑定;为了避免错误,开发过程中需要使用bind执行硬绑定this; 箭头函数自己没有this,他的this指向就会指向组件实例本身。

chunhuigao avatar Jan 19 '22 15:01 chunhuigao

react事件绑定

在jsx中传递的事件不是一个修饰符而是一个函数。onClick是一个中间量,所以在事件绑定中会出现this丢失指向window的现象,所以要通过bind将this绑定为实例

解决办法

  1. 组件中通过bind绑定this;
  2. 使用箭头函数声明方法;
  3. 在构造函数中提前绑定;
  4. 把事件调用写成回调函数;

792472461 avatar Jan 19 '22 15:01 792472461

  • 在使用ES6 classes或者纯函数时,React不会自动绑定this到当前组件上,需要手动实现this的绑定。

  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。所以箭头函数可以自动绑定定义此函数作用的this,因此不需要bind

  • 为了绑定事件的传参,用箭头函数,闭包保持绑定事件handleClick(i)对参数i的引用,等到执行时就可以传入正确的参数

renderA(i) {
    return (
      <A
        onClick={() => this.handleClick(i)}
      />
    );
 }

superjunjin avatar Jan 19 '22 15:01 superjunjin

react的事件绑定,当事件被触发时,this的值会执行undefined。当我们使用箭头函数时,则this指向当前所在的上下文。

alec1815 avatar Jan 19 '22 16:01 alec1815

react中使用标准函数会出现this指向为undefined而导致调用失败的情况出现。 在标准函数中,this引用的是调用当前方法的对象。 而react是运行在严格模式下的一个框架,为了达到兼容各浏览器平台以及更高效处理事件的目的,在react中的事件是经过封装处理的合成事件,其中onClick事件,在其内部实现中,是将当前函数作为回调函数调用,并在回调函数中使用apply更改this指向undefined。 因此,这个问题通常可以在constract中手动使用bind更改this指向当前的class类中来解决。 而在es6出现后,箭头函数中this引用的是定义箭头函数的上下文,所以在react中定义的函数就可以从标准函数改为箭头函数,就可以达到this直接指向当前类的目的

alienRidingCat avatar Jan 19 '22 16:01 alienRidingCat

  • react事件绑定传递的是一个中间变量,如果直接调用会导致this指向的丢失,这是javascript本来就有的问题
  • 使用箭头函数this指向当前类作用域,解决了上述问题

jj56313751 avatar Jan 19 '22 16:01 jj56313751

react 组件中,事件的handle 方法其实就相当于回调函数传参方式赋值给了 callback,在执行 click 事件时类似 element.addEventListener('click', callback, false ), handle 失去了隐式绑定的上下文,this 的值为 undefined。所以我们需要在 初始化调用 constructor 就通过 bind或者箭头函数绑定this

yanzefeng avatar Jan 19 '22 16:01 yanzefeng

React 中将处理程序作为回调传递后,会丢失上下文,导致 this 的值回退到默认绑定,又因为类声明和类表达式的主体是以严格模式运行,所以此时 this 的值为 undefined。 解决方案是通过 bind 进行显示绑定或者利用箭头函数编写方法或者作为回调调用方法。

定义时

class Foo extends React.Component{
  handleClick = () => {
    console.log(this); 
  }
 
  render(){
    return (
      <button type="button" onClick={this.handleClick}>
        Click Me
      </button>
    );
  }
}

ReactDOM.render(
  <Foo />,
  document.getElementById("app")
);

回调中

class Foo extends React.Component{
 handleClick(event){
    console.log(this);
  }
 
  render(){
    return (
      <button type="button" onClick={(e) => this.handleClick(e)}>
        Click Me
      </button>
    );
  }
}

ReactDOM.render(
  <Foo />,
  document.getElementById("app")
);

原因是在箭头函数的情况下,this 是有词法约束力的。这意味它可以使用封闭的函数上下文或者全局上下文作为 this 的值。

在箭头函数作为回调的例子中,箭头函数被包含在 render() 方法中,该方法由 React 在组件实例的上下文中调用。
这就是为什么箭头函数也可以捕获相同的上下文,并且其中的 this 值将正确的指向组件实例。

zhenyuWang avatar Jan 19 '22 16:01 zhenyuWang

react绑定事件,会将事件处理函数作为回调函数传给react内部,当我们触发点击的时候,react内部再去执行我们的这个回调函数,执行的时候,由于react这里是开启了严格模式的,this会指向undefined,那我们点击处理函数里的this就没办法正常用了。

那么为了解决这个问题,我们以下几种方式

  1. 使用bind方法将点击事件处理函数的this指针直接当前环境的this
  2. onClick事件直接绑定一个箭头函数
  3. 定义点击事件直接就定义为箭头函数

crazyyoung1020 avatar Jan 19 '22 17:01 crazyyoung1020

在 React 中绑定事件,会将事件的处理函数以回调函数的方式传给 React 内部,而当我们使用普通函数时,由于 this 是在调用时指向,而且 React 内部是使用严格模式,所以内部将 this 指向了 undefined

如果使用了箭头函数,因为箭头函数在定义时就确定了 this 指向,因此不会导致 this 指向 undefined 也可以使用 call、bind、apply 的方法显示绑定函数的 this 指向

rachern avatar Jan 19 '22 17:01 rachern

在react绑定的事件经过jsx转换最终到fiber的props上,这里就被转了一次,导致回调函数的this丢失,函数退化默认指向为undefined, 后面通过合成事件触发,又是使用fn.apply(undefined, arguments)执行,所以最终回调函数内this为undefined

声明类方法时使用箭头函数是最推荐的,因为类中的箭头函数总指向类实例

jiafei-cat avatar Jan 19 '22 18:01 jiafei-cat

  1. react中的事件绑定如果直接调用普通函数,那么普通函数的this是指向当前事件对象的this的,但是react源码中定义事件对象的this是undefined;
  2. 所以如果一定要使用普通函数,这个时候在事件初始化的时候改变函数this的指向,可以在constructor中通过bind将普通函数的this指定为当前class实例的this;
  3. 其实这个时候使用箭头函数是最方便的,因为箭头函数的this指向在定义它的时候就一定确定了是class实例的this指向,跟谁调用它无关。

guoshukun1994 avatar Jan 19 '22 18:01 guoshukun1994

React 的事件绑定说的其实就是我们定义了一个函数,然后传给 React 的框架,然后当事件发生的时候呢,React的框架就会调用这个函数。

那么这个函数的 this 指向,正常情况下,其实是由 React 的框架来决定的。React 框架它如果以构造函数的方式去调用这个函数,或者是以方法的方式去调用这个函数,或者以普通函数的方式去调用这个函数,都会有不同的 this 指向的情况发生。

在现实中呢,React 其实就是以 call(undefined) 的方式去调用了我们传给他的这个函数,也就是说this会指向 undefined。

所以,如果我们真的需要在这个回调函数里面使用 this 的话。如果我们真的需要在这个回调函数里面拥有一个符合我们自己需求的 this 的话。我们作为函数的定义者,其实是有权利以更高的优先级去指定 this 的,那么手段有两个,一个就是通过箭头函数,另外一个就是通过 bind。

rhythm022 avatar Jan 22 '22 14:01 rhythm022