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

时间:2017-05-14 21:05:07

标签: reactjs

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

“由于渲染性能影响,”在JSX属性中禁止使用Lambda“

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

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

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

3 个答案:

答案 0 :(得分:46)

绝对不是反模式。

Lambda(箭头函数)对渲染性能没有影响。

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

如果不实施shouldComponentUpdate,将箭头功能更改为绑定方法将无法提高性能。

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

另请注意,React具有无状态组件,甚至无法实现shouldComponentUpdate,因此它们始终会被渲染。

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

答案 1 :(得分:1)

据我所知,即使您没有使用React.PureComponentuseMemo,它也会影响性能。在组件的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]) } /> );

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

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>
  )
}

因此,现在,由于我们使用常量中的函数表达式来代替匿名函数(不能重用),因此React不会在每个要渲染的新组件上都重新创建新函数,并且垃圾收集器可以分片!

答案 2 :(得分:0)

我不确定为什么/不允许这样做,但是无论如何; Javascript允许我们在类似的代码块中声明函数

if (bookmarkItem.url) {
  console.log(makeIndent(indent) + bookmarkItem.url);
  bookmarkCreated(bookmarkItem.id, bookmarkItem.url);
} else {
  console.log(makeIndent(indent) + "Folder");
  indent++;
}

function mapCustomersToButton(c) { function handleBtnClick() { this.deleteCust(c.id); } return <Btn onClick={handleBtnClick} /> } return customers.map(mapCustomersToButton); 函数在handleBtnClick函数传递的c对象周围创建一个闭包;保存参考。

这等效于以下内容:

mapCustomersToButton