[英]'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 处理程序时,这将导致this
为window
。
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.