JSX属性中的Lambda是反模式吗?

Dav*_*ord 32 reactjs

我今天开始使用新的linter(tslint-react),它给了我以下警告:

"由于渲染性能影响,Lambdas在JSX属性中被禁止"

我知道这会导致每个渲染都创建一个新函数.而且它可以触发不需要的重新渲染,因为子组件会认为它的道具已经改变了.

但我的问题是,如何将参数传递给循环内的事件处理程序:

customers.map( c => <Btn onClick={ () => this.deleteCust(c.id) } /> );
Run Code Online (Sandbox Code Playgroud)

Sul*_*han 54

绝对不是反模式.

Lambdas(箭头函数)对渲染性能没有影响.

唯一有影响的是实施shouldComponentUpdate.true默认情况下,此函数返回,这意味着始终呈现组件.这意味着即使道具没有改变,组件仍然会再次渲染.这是默认行为.

如果不实现,将箭头函数更改为绑定方法将无法提高性能shouldComponentUpdate.

确实,不使用箭头函数可以简化实现,shouldComponentUpdate它们不应该使用,PureComponent但它们不是反模式.它们可以简化许多模式,例如在为函数添加其他参数时(例如,在您的示例中您正在执行的操作).

另请注意,React具有无状态组件,甚至无法实现shouldComponentUpdate,因此始终呈现它们.

在实际发现性能问题之前,请不要考虑性能影响.

  • @Koen.在更新DOM时,我认为`onClick`处理程序并不重要.React不直接将函数绑定到DOM,因为它有一个抽象层(带有合成事件).因此,更改函数应该对DOM没有影响,因为DOM不会更改. (3认同)

小智 5

据我所知,即使您不使用React.PureComponentor ,它也会对性能产生影响useMemo。当您在组件的 prop(JSX 属性)中定义匿名箭头函数(Lambda)时,在每个渲染上都会创建相同的函数,因此 JS 引擎无法重用它。这种娱乐不会降低性能,因为 JavaScript 的引擎垃圾收集器必须收集那些不必要的功能。

还有其他几种方法的行为相同。看看下面的例子:

#1 Lamba approach
customers.map( c => <Btn onClick={ () => this.deleteCust(c.id) } /> );

#2 bind apprach
customers.map( c => <Btn onClick={ this.deleteCust.bind(this, c.id) } /> );

#3 call approach
customers.map( c => <Btn onClick={ this.deleteCust.call(this, c.id) } /> );

#4 apply approach
customers.map( c => <Btn onClick={ this.deleteCust.apply(this, [c.id]) } /> );
Run Code Online (Sandbox Code Playgroud)

我会说推荐的方法是在被映射的组件内创建一个单独的函数。让我们稍微修改一下您的示例:

const Btn = ({ clicked, customer }) => {
  const buttonClickHandler = () => {
    clicked(customer.id)
  }
  return <button onClick={buttonClickHandler}>Click me!</button> 
}

const App = () => {
  return (
    <App>
      { customers.map(c => <Btn customer={c} clicked={deleteCust} />) }
    </App>
  )
}
Run Code Online (Sandbox Code Playgroud)

所以现在,由于我们在常量中使用函数表达式而不是匿名函数(不能重用),因此 React 不会在每个新组件重新渲染时重新创建新函数,垃圾收集器可以暂时停止!