1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 这就是为什么我们需要在React的类组件中绑定事件处理程序

这就是为什么我们需要在React的类组件中绑定事件处理程序

时间:2018-09-24 10:31:31

相关推荐

这就是为什么我们需要在React的类组件中绑定事件处理程序

by Saurabh Misra

索拉·米斯拉(Saurabh Misra)

这就是为什么我们需要在React的类组件中绑定事件处理程序 (This is why we need to bind event handlers in Class Components in React)

While working on React, you must have come across controlled components and event handlers. We need to bind these methods to the component instance using.bind()in our custom component’s constructor.

在使用React时,您必须遇到受控组件和事件处理程序。 我们需要在自定义组件的构造函数中使用.bind()将这些方法绑定到组件实例。

class Foo extends ponent{constructor( props ){super( props );this.handleClick = this.handleClick.bind(this);}handleClick(event){// your event handling logic}render(){return (<button type="button" onClick={this.handleClick}>Click Me</button>);}}ReactDOM.render(<Foo />,document.getElementById("app"));

In this article, we are going to find out why we need to do this.

在本文中,我们将找出为什么需要这样做。

I would recommend reading about.bind()here if you do not already know what it does.

如果您尚不知道.bind()我建议在这里阅读。

责备JavaScript,无法React(Blame JavaScript, Not React)

Well, laying blame sounds a bit harsh. This is not something we need to do because of the way React works or because of JSX. This is because of the way thethisbinding works in JavaScript.

好吧,怪罪听起来有些刺耳。 由于React的工作方式或JSX,我们不需要这样做。 这是因为this绑定在JavaScript中的工作方式。

Let’s see what happens if we do not bind the event handler method with its component instance:

让我们看看如果不将事件处理程序方法与其组件实例绑定在一起会发生什么:

class Foo extends ponent{constructor( props ){super( props );}handleClick(event){console.log(this); // 'this' is undefined}render(){return (<button type="button" onClick={this.handleClick}>Click Me</button>);}}ReactDOM.render(<Foo />,document.getElementById("app"));

If you run this code, click on the “Click Me” button and check your console. You will seeundefinedprinted to the console as the value ofthisfrom inside the event handler method. ThehandleClick()method seems to havelostits context (component instance) orthisvalue.

如果运行此代码,请单击“ Click Me”按钮并检查您的控制台。 你会看到undefined打印到控制台的值this从事件处理方法内部。handleClick()方法似乎丢失了其上下文(组件实例)或this值。

“ this”绑定在JavaScript中的工作方式(How ‘this’ binding works in JavaScript)

As I mentioned, this happens because of the waythisbinding works in JavaScript. I won’t go into a lot of detail in this post, but here is a great resource to understand how thethisbinding works in JavaScript.

正如我提到的,发生这种情况的原因是this绑定在JavaScript中的工作方式。 我不会在本文中详细介绍,但是这里是了解this绑定如何在JavaScript中工作的好资源。

But relevant to our discussion here, the value ofthisinside a function depends upon how that function is invoked.

但是与我们这里的讨论有关,this功能在函数内部的值取决于该函数的调用方式。

默认绑定(Default Binding)

function display(){console.log(this); // 'this' will point to the global object}display();

This is a plain function call. The value ofthisinside thedisplay()method in this case is the window — or the global — object in non-strict mode. In strict mode, thethisvalue isundefined.

这是一个简单的函数调用。 在这种情况下,在display()方法内部的this的值是非严格模式下的window对象或global对象。 在严格模式下,this值是undefined

隐式绑定(Implicit binding)

var obj = {name: 'Saurabh',display: function(){console.log(this.name); // 'this' points to obj}};obj.display(); // Saurabh

When we call a function in this manner — preceded by a context object — thethisvalue insidedisplay()is set toobj.

当我们以这种方式(在上下文对象之前)调用函数时,display()this值设置为obj

But when we assign this function reference to some other variable and invoke the function using this new function reference, we get a different value ofthisinsidedisplay().

但是,当我们给这个函数引用其他一些变量,并调用使用这个新功能的参考作用,我们得到的不同的值this里面display()

var name = "uh oh! global";var outerDisplay = obj.display;outerDisplay(); // uh oh! global

In the above example, when we callouterDisplay(), we don’t specify a context object. It is a plain function call without an owner object. In this case, the value ofthisinsidedisplay()falls back todefault binding.It points to the global object orundefinedif the function being invoked uses strict mode.

在上面的示例中,当我们调用outerDisplay(),我们没有指定上下文对象。 这是一个简单的函数调用,没有所有者对象。 在这种情况下,thisdisplay()内部的值将退回到默认binding。如果所调用的函数使用严格模式,则它指向全局对象或undefined

This is especially applicable while passing such functions as callbacks to another custom function, a third-party library function, or a built-in JavaScript function likesetTimeout.

在将诸如回调之类的函数传递给另一个自定义函数,第三方库函数或内置JavaScript函数(如setTimeout,这尤其适用。

Consider thesetTimeoutdummy definition as shown below, and then invoke it.

考虑如下所示的setTimeout虚拟定义,然后调用它。

// A dummy implementation of setTimeoutfunction setTimeout(callback, delay){//wait for 'delay' millisecondscallback();}setTimeout( obj.display, 1000 );

We can figure out that when we callsetTimeout, JavaScript internally assignsobj.displayto its argumentcallback.

我们可以发现,当我们调用setTimeout,JavaScript在内部将obj.display分配给其参数callback

callback = obj.display;

This assignment operation, as we have seen before, causes thedisplay()function to lose its context. When this callback is eventually invoked insidesetTimeout, thethisvalue insidedisplay()falls back todefault binding.

如我们之前所见,此分配操作导致display()函数失去其上下文。 当最终在setTimeout内部调用此回调时,display()this值将退回到默认binding

var name = "uh oh! global";setTimeout( obj.display, 1000 );// uh oh! global

显式硬绑定(Explicit Hard Binding)

To avoid this, we canexplicitly hard bindthethisvalue to a function by using thebind()method.

为避免这种情况,我们可以使用bind()方法将this明确绑定到函数。

var name = "uh oh! global";obj.display = obj.display.bind(obj); var outerDisplay = obj.display;outerDisplay();// Saurabh

Now, when we callouterDisplay(), the value ofthispoints toobjinsidedisplay().

现在,当我们调用outerDisplay()价值thisobjdisplay()

Even if we passobj.displayas a callback, thethisvalue insidedisplay()will correctly point toobj.

即使我们将obj.display作为回调传递,display()this值也将正确指向obj

仅使用JavaScript重新创建方案(Recreating the scenario using only JavaScript)

In the beginning of this article, we saw this in our React component calledFoo. If we did not bind the event handler withthis, its value inside the event handler was set asundefined.

在本文的开头,我们在名为Foo的React组件中看到了这一点。 如果我们不this绑定事件处理程序,则事件处理程序内部的值将设置为undefined

As I mentioned and explained, this is because of the waythisbinding works in JavaScript and not related to how React works. So let’s remove the React-specific code and construct a similar pure JavaScript example to simulate this behavior.

正如我提到和解释的那样,这是因为this绑定在JavaScript中起作用的方式,与React的工作方式无关。 因此,让我们删除特定于React的代码,并构建一个类似的纯JavaScript示例来模拟此行为。

class Foo {constructor(name){this.name = name}display(){console.log(this.name);}}var foo = new Foo('Saurabh');foo.display(); // Saurabh// The assignment operation below simulates loss of context // similar to passing the handler as a callback in the actual // React Componentvar display = foo.display; display(); // TypeError: this is undefined

We are not simulating actual events and handlers, but instead we are using synonymous code. As we observed in the React Component example, thethisvalue wasundefinedas the context was lost after passing the handler as a callback — synonymous with an assignment operation. This is what we observe here in this non-React JavaScript snippet as well.

我们不是在模拟实际的事件和处理程序,而是在使用同义代码。 正如我们在React Component示例中观察到的,thisundefined因为在将处理程序作为回调传递后上下文丢失了—与赋值操作同义。 这也是我们在此非React JavaScript代码段中观察到的内容。

“Wait a minute! Shouldn’t thethisvalue point to the global object, since we are running this in non-strict mode according to the rules of default binding?” you might ask.

“等一下!this值不应该指向全局对象,因为我们根据默认绑定规则以非严格模式运行此对象?” 你可能会问。

No.This is why:

不,这是为什么:

The bodies ofclass declarationsandclass expressionsare executed in strict mode, that is the constructor, static and prototype methods. Getter and setter functions are executed in strict mode.

类声明和类表达式的主体以严格模式执行,即构造函数,静态方法和原型方法。 Getter和Setter函数在严格模式下执行。

You can read the full article here.

您可以在此处阅读全文。

So, to prevent the error, we need to bind thethisvalue like this:

因此,为防止错误,我们需要像这样绑定this值:

class Foo {constructor(name){this.name = namethis.display = this.display.bind(this);}display(){console.log(this.name);}}var foo = new Foo('Saurabh');foo.display(); // Saurabhvar display = foo.display;display(); // Saurabh

We don’t need to do this in the constructor, and we can do this somewhere else as well. Consider this:

我们不需要在构造函数中执行此操作,也可以在其他地方执行此操作。 考虑一下:

class Foo {constructor(name){this.name = name;}display(){console.log(this.name);}}var foo = new Foo('Saurabh');foo.display = foo.display.bind(foo);foo.display(); // Saurabhvar display = foo.display;display(); // Saurabh

But the constructor is the most optimal and efficient place to code our event handler bind statements, considering that this is where all the initialization takes place.

但是考虑到这是所有初始化发生的地方,构造函数是编写我们的事件处理程序bind语句的最理想,最有效的地方。

为什么我们不需要为Arrow函数绑定'this'(Why don’t we need to bind ‘this’for Arrow functions?)

We have two more ways we can define event handlers inside a React component.

我们还有另外两种方法可以在React组件中定义事件处理程序。

Public Class Fields Syntax(Experimental)

公共类字段语法(实验性)

class Foo extends ponent{handleClick = () => {console.log(this); }render(){return (<button type="button" onClick={this.handleClick}>Click Me</button>);}} ReactDOM.render(<Foo />,document.getElementById("app"));

Arrow function in the callback

回调中的箭头功能

class Foo extends ponent{handleClick(event){console.log(this);}render(){return (<button type="button" onClick={(e) => this.handleClick(e)}>Click Me</button>);}}ReactDOM.render(<Foo />,document.getElementById("app"));

Both of these use the arrow functions introduced in ES6. When using these alternatives, our event handler is already automatically bound to the component instance, and we do not need to bind it in the constructor.

这两个都使用ES6中引入的箭头功能。 使用这些替代方法时,我们的事件处理程序已经自动绑定到组件实例,并且不需要在构造函数中绑定它。

The reason is that in the case of arrow functions,thisis boundlexically. This means that it uses the context of the enclosing function — or global — scope as itsthisvalue.

原因是在箭头函数的情况下,this是按词法绑定的。 这意味着它将封闭函数(或全局)范围的上下文用作this值。

In the case of the public class fields syntax example, the arrow function is enclosed inside theFooclass — or constructor function — so the context is the component instance, which is what we want.

对于公共类字段语法示例,箭头函数包含在Foo类(或构造函数)内部,因此上下文是组件实例,这正是我们想要的。

In the case of the arrow function as callback example, the arrow function is enclosed inside therender()method, which is invoked by React in the context of the component instance. This is why the arrow function will also capture this same context, and thethisvalue inside it will properly point to the component instance.

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

For more details regarding lexicalthisbinding, check out this excellent resource.

有关词法this绑定的更多详细信息,请查看此出色的资源 。

使长话短说(To make a long story short)

In Class Components in React, when we pass the event handler function reference as a callback like this

在React的Class Components中,当我们将事件处理函数的引用作为回调传递时,就像这样

<button type="button" onClick={this.handleClick}>Click Me</button>

the event handler method loses itsimplicitly boundcontext. When the event occurs and the handler is invoked, thethisvalue falls back todefault bindingand is set toundefined, as class declarations and prototype methods run in strict mode.

事件处理程序方法将失去其隐式绑定的上下文。 当事件发生并调用处理程序时,this值将返回默认绑定,并设置为undefined,因为类声明和原型方法以严格模式运行。

When we bind thethisof the event handler to the component instance in the constructor, we can pass it as a callback without worrying about it losing its context.

当我们将事件处理程序的this绑定到构造函数中的组件实例时,我们可以将其作为回调传递,而不必担心会丢失其上下文。

Arrow functions are exempt from this behavior because they uselexicalthisbindingwhich automatically binds them to the scope they are defined in.

箭头函数不受此行为的影响,因为它们使用词法this绑定this绑定会自动将它们绑定到定义它们的作用域。

翻译自: /news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。