React事件回调传参时,用函数柯里化替代匿名函数有效率优势吗?
在React事件回调中用柯里化代替匿名函数,效率上有优势吗?
先直接给结论:单纯这两种写法在效率层面几乎没有任何差异——本质上它们每次组件渲染时都会生成一个全新的函数实例,函数创建的开销、对React重渲染的影响都是一致的。
为什么这么说?先拆解两种写法的本质
看你的代码示例:
第一种匿名函数写法:
const doSomething = (arg1, arg2) => { // ...逻辑 } <div onClick={() => doSomething(arg1, arg2)} />
每次组件渲染时,都会创建一个新的箭头函数(就是() => doSomething(...)这个),作为onClick的回调传递给<div>。
第二种柯里化写法:
const doSomething = (arg1, arg2) => () => { // ...逻辑 } <div onClick={doSomething(arg1, arg2)} />
每次组件渲染时,会调用doSomething(arg1, arg2),而这个调用会返回一个全新的箭头函数——和第一种写法一样,最终传给onClick的还是每次渲染新生成的函数实例。
两者对效率的影响完全一致
- 函数创建开销:现代JavaScript引擎对函数实例的创建已经做了非常多优化,除非你在一个列表里渲染几千个这种组件,否则这点开销完全可以忽略。但不管是哪种写法,开销是一样的。
- React重渲染影响:如果这个
<div>是一个用React.memo包裹的自定义组件,那么每次onClick引用变化都会触发它的重渲染——两种写法都会导致引用变化,所以没有区别。
那怎么才真的能优化?
如果想要减少不必要的函数创建和子组件重渲染,你需要结合useCallback来缓存函数实例:
比如用useCallback包裹柯里化的返回:
const doSomething = (arg1, arg2) => () => { // ...逻辑 } const cachedCallback = useCallback(doSomething(arg1, arg2), [arg1, arg2]); <div onClick={cachedCallback} />
或者用useCallback包裹匿名函数:
const doSomething = (arg1, arg2) => { // ...逻辑 } const cachedCallback = useCallback(() => doSomething(arg1, arg2), [arg1, arg2]); <div onClick={cachedCallback} />
这两种写法才会在arg1和arg2不变时,复用同一个函数实例,避免不必要的子组件重渲染。
另外还有一种思路:把参数放到DOM的data-*属性里,然后在回调中通过事件对象获取,这样不需要传递参数,也就不需要每次创建新函数:
const handleClick = (e) => { const arg1 = e.target.dataset.arg1; const arg2 = e.target.dataset.arg2; doSomething(arg1, arg2); } <div data-arg1={arg1} data-arg2={arg2} onClick={handleClick} />
这种方式适合参数是字符串或可以转成字符串的场景,好处是handleClick可以用useCallback缓存(如果它不依赖其他变量的话)。
总结
单纯用柯里化代替匿名函数,在效率上没有任何优势——两者都是每次渲染生成新函数。想要优化,必须结合useCallback或其他缓存手段,或者调整参数传递的方式。
内容的提问来源于stack exchange,提问作者JovStern
相关产品推荐
相关产品推荐

