简体   繁体   English

function 与 class 反应组件中的事件处理程序的“this”上下文不同

[英]'this' context different for event handlers in function vs class react components

Why is 'this' (the context) different depending on whether I use a functional or class component in react?为什么'this'(上下文)会根据我在反应中使用功能组件还是 class 组件而有所不同? I understand how binding works and that my handler will take on the context of the onclick handler (or however it gets used in onclick) but I don't understand why the value is different for these 2 situations.我了解绑定的工作原理,并且我的处理程序将采用 onclick 处理程序的上下文(或者它在 onclick 中使用),但我不明白为什么这两种情况的值不同。 The functional component prints the window object while the class component prints undefined.功能组件打印 window object 而 class 组件打印未定义。

How is the synthetic onclick event defined?如何定义合成 onclick 事件? What is its context?它的背景是什么? What does it do with its callback?它的回调有什么作用?

export default function App() {
  const handleClick = function () {
    console.log(this);
  };

  return (
    <div className="App">
      <button onClick={handleClick}>HandleClick Functional</button>
      <Toggle />
    </div>
  );
}

class Toggle extends React.Component {
  handleClick() {
    console.log(this);
  }

  render() {
    return <button onClick={this.handleClick}>HandleClick Class</button>;
  }
}

codesandbox link: https://codesandbox.io/s/onclick-context-test-ievog6?file=/src/App.js代码框链接: https://codesandbox.io/s/onclick-context-test-ievog6?file=/src/App.js

TL;DR - This looks like a bug with CodeSandbox. TL;DR - 这看起来像 CodeSandbox 的一个错误。 Your React function component code ends up running in non-strict mode, which causes your this value to default to the global object instead of undefined as it should be.您的 React function 组件代码最终以非严格模式运行,这导致您的this值默认为全局 object 而不是应为的undefined

This behaviour is pretty odd.这种行为很奇怪。 But like qrsngky has correctly pointed out in the comments above, the issue is mainly to do with strict-mode and a result of how CodeSandbox does error handling.但就像qrsngky在上面的评论中正确指出的那样,问题主要与严格模式有关,并且是 CodeSandbox 如何进行错误处理的结果。 Below I've outlined my observations on why your code is behaving as it is.下面我概述了我对您的代码为何如此运行的观察。

Functions declared with the function keyword have their own value for this (their own "this binding").使用function关键字声明的函数有自己的this值(它们自己的“this 绑定”)。 How that value for this is determined is based on how the function is executed.如何确定this值取决于 function 的执行方式。 Methods such as .call() and .apply() are able to set the this value for the function they execute. .call( .call().apply()等方法能够为它们执行的 function 设置this值。

In strict-mode code, using fn.apply(undefined) results in the function fn being executed and the this value within fn being set to undefined .在严格模式代码中,使用fn.apply(undefined)会导致执行 function fn并将fn中的this值设置为undefined However, in non-strict mode code, using fn.apply(undefined) results in the this value being set to theglobal object , which in browsers is the window object.但是,在非严格模式代码中,使用fn.apply(undefined)会导致this值设置为全局 object ,在浏览器中为window object。 When React invokes your onClick handler function ( func ), it invokes it by doing func.apply(context, ...) , with a context set to undefined (you can see this via a debugger):当 React 调用您的onClick处理程序 function ( func ) 时,它通过执行func.apply(context, ...)来调用它,并将context设置为undefined (您可以通过调试器看到这一点):

在此处输入图像描述

At this point, you may be thinking that your code doesn't use the "use strict" directive anywhere, so it makes sense that when your function is called with a this of undefined it defaults to the global object window .此时,您可能会认为您的代码在任何地方都没有使用"use strict"指令,因此当您的 function 使用this of undefined调用时,它默认为全局 object window However, it's not as straightforward as that;).但是,它并不像那样简单;)。 While it may not look like any of your code is running in strict mode, it is actually classified as strict-mode code.虽然看起来您的任何代码都没有在严格模式下运行,但实际上它被归类为严格模式代码。 That's because ES6 Modules (what you've written your react code in), automatically run in strict-mode .那是因为ES6 模块(您编写反应代码的内容) 会自动在 strict-mode 下运行 Similarly, classes also automatically run in strict-mode .同样, 类也自动以严格模式运行 So that begs the question as to why your code is showing window then if your code should actually be running in strict-mode.所以这就引出了一个问题,即为什么你的代码显示window那么你的代码是否真的应该在严格模式下运行。

When React code is written it needs to be transpiled into code that the browser can understand and execute.编写 React 代码时,需要将其转换为浏览器可以理解和执行的代码。 What seems to have occurred is that when your react code was transpiled, CodeSandbox has added a try-finally wrapper around your react code (you can see this using a debugger with source-maps disabled):似乎发生的事情是,当您的反应代码被转译时,CodeSandbox 在您的反应代码周围添加了一个try-finally 包装器(您可以使用禁用源映射的调试器看到这一点):

try {
  "use strict";
   ...
   function App() {
     const handleClick = function() {
       console.log(this);
     }
   }
...
} finally {
 ...
}

We can see that CodeSandbox has attempted to wrap your code within a try-finally block, where the try block runs in "strict mode" to try and match the same strict mode behavior automatically applied by the ES6 module your code is originally written in. However, applying "use strict" in a block {} that isn't associated with a function has no effect on the code's strictness (see here for rules on strict mode).我们可以看到 CodeSandbox 尝试将您的代码包装在 try-finally 块中,其中try块以“严格模式”运行,以尝试匹配最初编写代码的 ES6 模块自动应用的相同严格模式行为。但是,在与 function 无关的块{}中应用"use strict"对代码的严格性没有影响(有关严格模式的规则,请参见 此处)。 As a result, the try-finally wrapper that CodeSandbox is applying ends up running your code in non-strict/sloppy mode.因此,CodeSandbox 应用的 try-finally 包装器最终会以非严格/草率模式运行您的代码。 This causes this to be window when React calls your onClick handler with undefined .当 React 使用undefined调用您的 onClick 处理程序时,这将导致thiswindow

On the other hand, your class still works as expected because in the transpiled code it remains as a class , so the strict-mode behavior around classes remains, and so you see undefined as expected.另一方面,您的class仍然按预期工作,因为在转译的代码中它仍然是class ,因此围绕类的严格模式行为仍然存在,因此您会看到undefined的预期。


When using React functional components, however, you shouldn't need to refer to this , and instead can use hooks such as useState() to manage things like state.但是,在使用 React 功能组件时,您不需要参考this ,而是可以使用诸如useState()类的钩子来管理诸如 state 之类的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM