我今天开始使用新的linter(tslint-react),它给了我以下警告:
“由于渲染性能影响,”在JSX属性中禁止使用Lambda“
我知道这会导致每个渲染都创建一个新函数。并且它可以触发不需要的重新渲染,因为子组件会认为它的道具已经改变了。
但我的问题是,如何将参数传递给循环内的事件处理程序:
customers.map( c => <Btn onClick={ () => this.deleteCust(c.id) } /> );
答案 0 :(得分:46)
绝对不是反模式。
Lambda(箭头函数)对渲染性能没有影响。
唯一有影响的是shouldComponentUpdate
的实施。默认情况下,此函数返回true
,表示始终呈现组件。这意味着即使道具没有改变,组件仍然会再次渲染。这是默认行为。
如果不实施shouldComponentUpdate
,将箭头功能更改为绑定方法将无法提高性能。
确实,不使用箭头函数可以简化shouldComponentUpdate
的实现,它们不应与PureComponent
一起使用,但它们不是反模式。它们可以简化许多模式,例如在为函数添加其他参数时(例如,您在示例中执行的操作)。
另请注意,React具有无状态组件,甚至无法实现shouldComponentUpdate
,因此它们始终会被渲染。
在实际发现性能问题之前,请不要考虑性能影响。
答案 1 :(得分:1)
据我所知,即使您没有使用React.PureComponent
或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]) } /> );
我会说推荐的方法是在要映射的组件内部创建一个单独的函数。让我们修改一下您的示例:
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