ReactJS - 行内箭头函数性能

3

我读到过在组件内部使用箭头函数会导致性能问题,因为每次重新渲染组件时都会重新创建这个函数。

在我的代码中出现了这种情况。

render() {
   return (
       <View
          onLayout={(event) => {
             this.itemHeights[index] = event.nativeEvent.layout.height;
          }}  
       >
     ...
   )
 }

我考虑这样做以获得更好的性能:
getItemHeight = (index, {nativeEvent: {layout: {height}}}) => this.itemHeights[index] = event.nativeEvent.layout.height;

render() {
   return (
       <View
          onLayout={(event) => getItemHeight(index, event)}  
       >
     ...
   )
 }

但我不确定这是否更好……因为我需要在内联函数中调用一个函数。我这样做是因为我需要参数索引,所以不能这样做:

 <View
    onLayout={getItemHeight}  
 >

我知道这可能不算太贵,但对于我的使用情况来说非常昂贵,因为我必须实时重新渲染项目。你有什么想法吗?
1个回答

3

声明 vs 执行

首先我认为你在混淆两件不同的事情。函数的声明与函数的执行是不同的。

此外,组件并不会一直重新渲染,仅因为一个函数在渲染函数返回中被重新声明。

声明函数和执行函数对性能影响的差异也非常大。

引用稳定函数 vs 内联函数

所以,在你的第一个示例中,你正在为 View 组件重新声明一个函数。这基本上重置了 onLayout 属性的值,因为内联函数不是引用稳定的。

~~在第二个示例中(我想这是一个类组件),您正在使用引用稳定函数,因此 onLayout 的属性值保持不变。~~

更新:实际上这是不正确的,我的错误。你仍在使用不稳定的函数。但是你可以像这样将它提到类成员中:

public getItemHeight(index, {nativeEvent: {layout: {height}}}) { 
  this.itemHeights[index] = event.nativeEvent.layout.height;
}

// ...
// ... inside the render function:
return {
  <View onLayout={this.getItemHeight}></View>
}

但我并不确定这是否更好......因为我必须在内联函数中调用一个函数。我之所以这样做是因为我需要参数索引,所以我不能这样做:

实际上,这种说法是不正确的。您也可以使用定义的函数获取索引,就像我上面展示的那样。 使用此代码,您只需将属性引用传递给要通过回调调用的函数即可。这将很好地填充参数。

组件何时重新渲染?

当存在属性或状态更改时,组件会重新渲染。 因此,在您的第一个示例中,仅当父组件需要重新渲染时,View组件才会重新渲染。因此,父级呈现并因此评估其子组件。这确实触发了View组件的渲染函数,并替换了onLayout的函数。

在您的第二个示例中(考虑我上面建议的代码更改),View组件不会触发其渲染函数,因为onLayout的属性值没有更改。

但这并不意味着,您的第一个示例一定会导致DOM更改和重绘(这是React内部的不同算法)。DOM更改将是真正昂贵的部分。

重新渲染 vs 重绘

重新渲染是React在内部运行的过程。React只会触发需要重新渲染的组件的渲染函数。但是在运行时实际页面内的重绘仅在结果DOM与之前不同的情况下发生。

您可以在React文档中阅读更多关于此的内容:https://reactjs.org/docs/reconciliation.html

那么什么时候需要使用引用稳定的函数?

我认为你不应该过早地优化这些东西。它可能会使代码变得臃肿,并引入不必要的复杂性。

这里还有一整部分内容:https://reactjs.org/docs/optimizing-performance.html#avoid-reconciliation

如果不影响性能,为什么要微调优化呢? 仅仅因为你读到了内联函数每次都会被重新创建(顺便说一下,这也适用于非箭头函数。是内联声明使其每次都会被重新创建),因此渲染函数每次都会被触发,并不总是意味着React必须进行重绘或者会带来很大的性能影响。

所以,当没有问题时,不要过早地在小的性能提升上摆弄。
基于React的应用程序是一个庞大的代码集合。一旦遇到性能问题,就会有很多大局问题需要解决。

此外,组件并不会一直重新渲染,仅仅因为一个函数在渲染函数的返回值中被重新声明。我正在使用该组件在一个FlatList中,该列表会移除视口之外的组件,这一点我在问题中没有明确说明,这是我的错误。无论如何,您解决了我的疑惑。谢谢。 - Victor Molina
1
同样的原则也适用于FlatList。在FlatList中最昂贵的操作是UI元素本身的交换。你的函数声明方式基本上与此无关。 - Johannes Klauß

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接