我应该在哪里绑定 React 组件中的方法?

Posted

技术标签:

【中文标题】我应该在哪里绑定 React 组件中的方法?【英文标题】:Where should I bind methods in React component? 【发布时间】:2019-02-10 23:00:15 【问题描述】:

我现在学习 React 并注意到很多人将他们的方法绑定在构造函数中。

像这样:

class MyComponent extends React.Component 
  constructor() 
    super();
    this.myMethod = this.myMethod.bind(this);
  

  render() 
    <button onClick=this.myMethod>Click me</button>
  

  myMethod() 
    // do something
  

但我习惯了这样写:

render() 
    <button onClick=this.myMethod.bind(this)>Click me</button>

有几个人告诉我,使用第二种方法是一种糟糕的体验。

那么你能告诉我第一种方法和第二种方法之间的区别吗?有什么优点和缺点吗?还是性能问题?

【问题讨论】:

由此引起的性能影响将是最小的。更重要的是在 JSX 中减少 javascript 代码,使其更具可读性。 根据我在第二个示例中的理解,您每次调用 render 时都会绑定并创建一个新函数,但我不确定这一点,如果有人知道它是否正确,请随意纠正我。 @BrunoMazzardo 你是对的。每次调用 render 时都会创建一个新函数。这将导致依赖道具的孩子重新渲染,因为新对象正在发生变化。 很好,我推荐这个链接来看看其他人解决这个问题medium.freecodecamp.org/… 这个话题在许多其他关于 React 的资源中被无限地讨论,你可以在网上找到它真的没有必要在这里 【参考方案1】:

你是对的,别人告诉你的也是对的。

鼓励你在构造函数中进行绑定,因为构造函数每个组件只调用一次,所以如果你在构造函数中进行绑定,它只会在 Webpack bundle.js 文件中创建一个新对象/函数,因此影响不大

不鼓励您直接在渲染中进行绑定,因为组件渲染有多种原因,例如当您执行 setState 时,当您的组件收到新的道具时,您的组件将渲染很多次。因此,由于您在组件渲染时直接在渲染中绑定,因此每次在 Webpack bundle.js 中都会创建一个新函数,并且您的捆绑文件大小会增加,并且当您的应用程序包含数千个组件并且如果您直接在其中进行绑定时,这会影响性能在每个组件中渲染。

所以建议你只在构造函数中进行绑定。希望澄清

【讨论】:

【参考方案2】:

我从 eslint-plugin-react 文档中获取了这个:

JSX 属性中的绑定调用或箭头函数将在每个渲染上创建一个全新的函数。这对性能不利,因为它会导致垃圾收集器被调用的方式超出必要的程度。如果将一个全新的函数作为 prop 传递给组件,该组件使用对 prop 的引用相等性检查来确定它是否应该更新,也可能导致不必要的重新渲染。

作为我的旁注,在 JSX 中使用 this 也会令人困惑。我鼓励你看看这个文档:https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

【讨论】:

【参考方案3】:

您应该避免在渲染中使用箭头函数和绑定。它破坏了性能 shouldComponentUpdate 和 PureComponent 等优化。

对于出色的阅读和演示,您可能需要参考 this.

【讨论】:

在 render 中使用 Function.prototype.bind 绑定会在每次组件呈现时创建一个新函数,这可能会对性能产生影响另外在 render 中使用箭头函数绑定会在每次组件呈现时创建一个新函数,这可能会破坏基于严格身份比较的优化。【参考方案4】:

第一种方法在性能方面是正确的,因为在每次渲染时,此 onClick 道具将指向同一个对象,而第二个示例中的情况并非如此。


如果你看下面的例子,你会看到当我增加计数器时,MyPureCompOne 不会渲染,但MyPureCompTwo 会。因为每次&lt;App&gt; 组件渲染时,MyPureCompTwo 的 props handleClick 都被分配了一个新的函数对象,这就是为什么作为纯组件对 props 的浅层比较是错误的并且它会渲染。不需要此渲染。但MyPureCompOne 的情况并非如此,因为每次App 渲染时,handleClick 道具仍然指向相同的函数对象(this.handleClickOne),该对象是在App 第一次挂载时创建的。

class MyPureCompOne extends React.PureComponent 
  render() 
    console.log("rendring component one");
    return <button onClick=this.props.handleClick>First Button</button>
  


class MyPureCompTwo extends React.PureComponent 
  render() 
    console.log("rendring component two");
    return <button onClick=this.props.handleClick>Second Button</button>;
  


class App extends React.Component 
  constructor(props) 
    super(props);
    this.state = 
      count: 0
    ;
    this.handleCountChange = this.handleCountChange.bind(this);
    this.handleClickOne = this.handleClickOne.bind(this);
  

  handleCountChange() 
    this.setState(prevState => (
      count: prevState.count + 1
    ));
  

  handleClickOne(e) 
    console.log("Clicked..");
  

  handleClickTwo() 
    console.log("Clicked..");
  

  render() 
    const  count  = this.state;
    return (
      <div>
        <button onClick=this.handleCountChange>Change Counter</button>
        <MyPureCompOne handleClick=this.handleClickOne />;
        <MyPureCompTwo handleClick=this.handleClickTwo.bind(this) />
      </div>
    );
  


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>


<div id='root'></div>

【讨论】:

【参考方案5】:

您应该在构造函数中绑定,因为第二种方式会在每次渲染时创建一个新函数。

但是有一个更好的方法可以简单地避免绑定。使用箭头函数。

class MyComponent extends React.Component 
  constructor() 
    super();
  

  render() 
    <button onClick=this.myMethod>Click me</button>
  

  myMethod = ()=> 
    // do something
  

让我们看看Redux的创建者Dan Abramovthinks about bind vs arrow functions-

Question:

在性能方面,使用箭头有什么区别 使用 es6 类时手动绑定函数和绑定?使用箭头 函数方法不在类原型上,它将在 仅类实例。使用 bind 会将方法附加到类 原型。听起来手动绑定会有更好的性能, 这是否意味着我们应该考虑使用 bind 而不是 arrow 类方法的函数?

非常感谢任何建议或cmets!

那么在性能方面,你会推荐使用

class MyComponent 扩展 React.Component constructor(props) 超级(道具)

方法A = () => ...

class MyComponent 扩展 React.Component constructor(props) 超级(道具) this.methodA = this.methodA.bind(this)

methodA() ...

Answer:

这两种写法是等价的。 (第二个是 编译到第一个。)

使用绑定会将方法附加到类原型。

在您的示例中,您仍然将函数附加到实例:

this.methodA = this.methodA.bind(this)

所以它们本质上是一样的。

在 Facebook,我们使用第二种方式(“类属性”),但请注意 这仍然是实验性的,不是 ES6 的一部分。如果你只想 坚持使用稳定的语法,然后你可以手动绑定它们。

【讨论】:

每次渲染组件时,如果箭头函数不在外部类中,它也会创建一个新函数。请看这个帖子***.com/questions/52031147/… @Think-Twice 我在这里指的是类级别的箭头函数。【参考方案6】:

这会导致在每个render 调用上创建一个新的绑定函数:

render() 
    <button onClick=this.myMethod.bind(this)>Click me</button>

请注意,如果myMethod 在多个地方使用,则需要多次调用bind,并且如果缺少bind 之一,可能会导致未绑定的回调。

虽然这会在组件实例化上创建绑定函数:

  constructor() 
    super();
    this.myMethod = this.myMethod.bind(this);
  

推荐第二个选项。

autobind 这样的装饰器可以用来跳过构造函数中的myMethod 显式赋值。

正如this answer 中所解释的,带有bind 的原型方法比箭头实例方法的缺点更少,通常是首选方法。

【讨论】:

以上是关于我应该在哪里绑定 React 组件中的方法?的主要内容,如果未能解决你的问题,请参考以下文章

React-事件绑定

为啥我必须将它绑定到 Reactjs 的类组件中的方法

箭头函数“this”绑定在 React 组件中不起作用 [重复]

无法理解react.js中的处理事件[关闭]

React.js 中的 OnClick 事件绑定

React.js 中的 OnClick 事件绑定