React 事件处理程序中 this 的值

Posted

技术标签:

【中文标题】React 事件处理程序中 this 的值【英文标题】:Value of this in React event handler 【发布时间】:2015-06-26 05:48:04 【问题描述】:

由于某种原因,this 的值在反应事件处理程序中丢失了。阅读文档,我认为 react 在这里做了一些事情以确保将其设置为正确的值

以下内容不像我预期的那样工作

import React from 'react';

export default class Observer extends React.Component 

    handleClick() 
        console.log(this); //logs undefined
    
    render() 
        return (
            <button onClick=this.handleClick>Click</button>
        );
    

但这确实:

import React from 'react';

export default class Observer extends React.Component 

    handleClick() 
        console.log(this); //logs Observer class instance
    
    render() 
        return (
            <button onClick=this.handleClick.bind(this)>Click</button>
        );
    

React 和 ES6 对我来说是新的,但这似乎不是正确的行为?

【问题讨论】:

为什么不是正确的行为? jsx 是否过多地掩盖了您为 onClick 创建的函数? 这与 ES6 无关。它在 ES5 中也不起作用。 @Bergi Accepted 答案另有说明。在 ES5 中,您将使用 React.createClass 并且您不必手动绑定。所以是的,这与使用 ES6 创建 React 组件的 OP 有关。 @StijndeWitt:当然,这是特定于框架的。可以编写一个(失败的)ES5 构造函数,它等效于没有React.createClass 的ES6 class,并且仍然可以在ES6 中使用React.createClass @Bergi 是的,但是 Facebook 本身提到了这个确切的问题,这是 从 React ES5 转换到 React ES6 时需要注意的事情之一,可以这么说与 ES6 无关,这很奇怪。另外,是的,它是特定于框架的,但这个问题被标记为reactjsreact-jsx 是有原因的。问题特定于框架的。最后,Facebook 建议 React.createClass 仅用于 ES5,并明确建议不要将其用于 ES6。 【参考方案1】:

如果您使用新的 class 语法,这对于 javascript 和 React 来说是正确的行为。

v0.13.0 中的autobinding feature does not apply to ES6 classes。

所以你需要使用:

 <button onClick=this.handleClick.bind(this)>Click</button>

或其他技巧之一:

export default class Observer extends React.Component 
  constructor() 
    super();
    this.handleClick = this.handleClick.bind(this);
  
  handleClick() 
    /* ... */
  
  render() 
      return <button onClick=this.handleClick>Click</button>
  

【讨论】:

编辑了您的答案,以阐明自动绑定在所有版本的 React 中继续与 React.createClass 一起使用。 感谢本的澄清。 请注意,在您链接的文档中,您还提供了另一个使用 ES7 类属性创建箭头函数处理程序的解决方案,例如 handleClick = (e) =&gt; ,然后在构造函数或任何地方都不需要 bind 调用。 【参考方案2】:

公认的答案很好,我在 ES6 中使用了很多,但我只想添加另一个我们在 ES7 中拥有的“更现代”的解决方案(在 React component class auto-binding notes 中提到):使用箭头函数作为 @987654322 @,那么你不需要在任何地方绑定或包装你的处理程序。

export default class Observer extends React.Component 
  handleClick = (e) => 
    /* ... */
  
  render() 
      return <button onClick=this.handleClick>Click</button>
  

这是迄今为止最简单、最干净的解决方案!

【讨论】:

onClick=e =&gt; this.handleClick(e) 不是更有效率吗?我相信它和this.handleClick = this.handleClick.bind(this)几乎是一样的,只是后者更多的是双打。 我的示例没有使用.bind(),它将粗箭头定义为类属性并简单地将其传递给回调属性。我认为这比在回调道具的每次渲染中定义箭头函数更有效,并且输入更少,特别是如果您想在渲染函数的多个位置使用处理程序。【参考方案3】:

正如其他人所说,React 在使用 ES6 类时不会自动将方法绑定到实例。也就是说,我会养成在事件处理程序中始终使用箭头函数的习惯,例如:onClick=e =&gt; this.handleClick()

代替:onClick=this.handleClick.bind(this)

这是因为这意味着您可以在测试中用 spy 替换 handleClick 方法,这是您使用 bind 时无法做到的。

【讨论】:

在您的箭头示例中,handleClick 方法不会将 DOM 元素作为参数,除非您明确传递它对吗? 对,handleClick函数需要onClick=e =&gt; this.handleClick(e.target)才能获取被点击的元素。

以上是关于React 事件处理程序中 this 的值的主要内容,如果未能解决你的问题,请参考以下文章

无法在事件处理程序中访问 React 实例(this)[重复]

从事件处理程序回调调用的函数中“this”的值?

React事件处理程序继承

React事件处理

在 React 事件处理程序中使用 .bind() 时出错

react之事件处理