【问题标题】:Should I call a function on every render or use arrow functions in a react class component?我应该在每个渲染上调用一个函数还是在反应类组件中使用箭头函数?
【发布时间】:2020-04-15 13:46:49
【问题描述】:

我有以下情况

export default class MyComponent extends Component {

    myFunc = dynamicKey => {
        // do something with the dynamic key
    }

    render() {

        return (
            <Foo>
                <button onClick={e => this.myFunc(someDynamicKey1)} /> 
                <button onClick={e => this.myFunc(someDynamicKey2)} /> 
                <button onClick={e => this.myFunc(someDynamicKey3)} /> 
                {/* ... */}
            </Foo>
        )
    }
}

这是一个非常常见的情况,但它并不好,因为在每次渲染时它都会创建箭头函数。

因此,作为一种解决方法,我创建了一个函数,该函数使用该键返回另一个函数。

export default class MyComponent extends Component {

    myFunc = dynamicKey => e => {
        // do something with the dynamic key
    }

    render() {

        return (
            <Foo>
                <button onClick={this.myFunc(someDynamicKey1)} /> 
                <button onClick={this.myFunc(someDynamicKey2)} /> 
                <button onClick={this.myFunc(someDynamicKey3)} /> 
                {/* ... */}
            </Foo>
        )
    }
}

现在我不是在每次渲染时都创建一个新函数,而是在每次渲染时调用一个新函数。

现在我不确定该使用哪一个。在每次渲染时调用一个函数是一种不好的做法吗?我应该使用箭头函数吗?

【问题讨论】:

  • 您可能想阅读这个问题stackoverflow.com/questions/29810914/…
  • 与代码中的这种差异相比,呈现本身(更新 DOM)更加耗时。而且很可能是 JS 解析器无论如何都会优化这段代码,所以实际上并不是每次都创建就地回调函数。所以我想说:不要担心这个,除非你能测量出时间上的差异。
  • @AtinSingh 这是一个很好的阅读问题,但不幸的是不是我的情况。我不能制作子对象,因为它只是一个按钮。创建一个只处理它的包装器会很奇怪。
  • @AtinSingh 我刚刚编辑了我的问题,所以它看起来更真实,更好地展示了我所处的情况。
  • 我很困惑,为什么您要在该组件中单击三个按钮来访问相同的功能?难道你不能只拥有一个函数,然后动态地将密钥传递给该函数吗?如果你能解释一下,那会有所帮助。我通常这样做的方式是这样的:onClick={this.myFunc.bind(this)}。这样我就不会创建箭头函数。

标签: javascript reactjs arrow-functions


【解决方案1】:

使用curried function时,可以在当前作用域上使用its closure

export default class MyComponent extends Component {
    state = {
      counter: 42
    }
    myFunc = dynamicKey => e => {
        // closure on the specific this.state.counter value at time of render.
    }
}

在每次渲染时返回一个新函数,它的闭包是在最近的范围

export default class MyComponent extends Component {
    state = {
      counter: 42
    }
    myFunc = dynamicKey => {
        // closure on this.state.counter value
    }
}

因此,这取决于用例是什么。 问问自己该函数是否需要特定值或最近的值。

注意:如果在每次渲染时都重新声明了函数,这将成为“函数和柯里化函数之间的区别”的问题,对于 React 来说这并不重要,因为两个函数体都会被执行。所以只有通过记忆函数(不要用相同的参数调用函数),你可以得到任何明显的差异。

【讨论】:

  • 这不会影响任何事情,因为当任何状态发生变化时,它会再次调用该函数并且它将是相同的值。它永远不会在我的函数中出现状态不同步的情况。 value at time of render 将始终与 value 相同。
  • 如果用相同的参数再次调用它,它确实没有效果,而且它们的作用相同(你可以查看维基百科页面,它变成了一个关于函数之间有什么区别的问题和咖喱一个),但是如果你记住这个函数,你可以实现上面的闭包。
【解决方案2】:

您可以缓存您的事件处理程序。

class SomeComponent extends React.Component {
    // Each instance of SomeComponent has a cache of click handlers
    // that are unique to it.
    clickHandlers = {};
    // Generate and/or return a click handler,
    // given a unique identifier.
    getClickHandler = (key) => {
     // If no click handler exists for this unique identifier, create one.
     if (!this.clickHandlers[key])){
      this.clickHandlers[key] = () => alert(key);
      }
       return this.clickHandlers[key];
    }

   render() {
    return (
        <ul>
          {this.props.list.map(listItem =>
          <li key={listItem.text}>
          <Button onClick={this.getClickHandler(listItem.text)} />
        </li>
          )}
       </ul>
     );
  }
}

查看以下article

如果你使用 React 钩子,那么:

const Button = props => {
  const onClick = React.useMemo(() => {
  alert(listItem.text)
   }, [listItem.text]);
  }
 return <button onClick={onClick}>click</button>
}

如果您的函数不依赖于您的组件(没有 this 上下文),您可以在组件之外定义它。您的组件的所有实例都将使用相同的函数引用,因为函数在所有情况下都是相同的。

与前面的示例相比,createAlertBox 在每次渲染期间保持对内存中相同位置的相同引用。因此,按钮永远不必重新渲染。

虽然 Button 可能是一个小型、快速渲染的组件,但您可能会在大型、复杂、渲染缓慢的组件上看到这些内联定义,它确实会拖累您的 React 应用程序。最好不要在 render 方法中定义这些函数。

如果您的函数确实依赖于您的组件,因此您无法在组件外部定义它,您可以将组件的方法作为事件处理程序传递:

在这种情况下,SomeComponent 的每个实例都有一个不同的警报框。 Button 的单击事件侦听器需要对 SomeComponent 是唯一的。通过传递 createAlertBox 方法,SomeComponent 是否重新渲染无关紧要。消息道具是否改变甚至都没有关系! createAlertBox 在内存中的地址不会改变,这意味着 Button 不必重新渲染,可以节省处理时间,提高应用程序的渲染速度。

对于动态函数

在这种情况下,您有可变数量的按钮,创建可变数量的事件侦听器,每个事件侦听器都有一个独特的功能,您在创建 SomeComponent 时不可能知道是什么。你怎么可能解决这个难题?

进入记忆化,或者更简单地称为缓存。对于每个唯一值,创建并缓存一个函数;对于该唯一值的所有未来引用,返回之前缓存的函数。

【讨论】:

  • “仅链接”的答案在这里没有用。
  • 链接中的代码示例甚至不可见!
  • 谢谢..添加了更多解释性的 sn-p 并更改了链接
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
  • 2017-09-21
  • 2019-09-15
  • 1970-01-01
  • 2022-10-15
  • 1970-01-01
相关资源
最近更新 更多