有关 react 的两个小问题。
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [num, setNum] = useState(0);
const handleClick = () => {
setNum(num + 1);
};
return (
<React.Fragment>
<span>{num}</span>
<button className="button1" onClick={handleClick}>
Click Me
</button>
<button className="button2" onClick={() => setNum(num + 1)}>
Click Me Again
</button>
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
</React.Fragment>
);
}
我忘记在哪里看到的(年纪大了,记性不太好),在以前 class component 的时代,不推荐 button2 的写法,就是把函数体直接赋值给 button's onClick 。因为这样会使得每次 button2 都有变化,会 re-render 。在大的项目 /组件多的情况下,会有性能问题。一般是建议在 class 里面定义一个函数,然后赋值给 button's click.
现在来到 function component 时代,当 button 被点击的时候,会触发 function app 被重新调用,handleClick 也会被重新生成,这个时候,button1 和 button2 的用法,还有区别么?不过,当 handleClick 比较复杂时,应该可以通过 useCallback 提高性能。虽然 const handleClick 是一个新的变量,但函数体被记忆 /缓存了。
const handleClick = useCallback(() => { ... });
另,我还“隐约”记得,button1 的写法,当用户点击 button 时,会触发“两”次 render,我不记得为什么了?是我记错了么?
最后,有没有什么 debug 方法,能够知道,比如,我点击 button1 后,跟踪一下,触发了多少次 render ?
谢谢!
1
kop1989 2021-06-24 16:17:01 +08:00
|
2
auroraccc 2021-06-24 16:22:29 +08:00
我理解 b1b2 没区别了
|
3
lxzxl 2021-06-24 19:07:36 +08:00 via iPhone
你这么写 useCallback 没用,setNum 传函数才行
|
4
lisianthus 2021-06-24 20:06:49 +08:00
>现在来到 function component 时代,当 button 被点击的时候,会触发 function app 被重新调用,handleClick 也会被重新生成,这个时候,button1 和 button2 的用法,还有区别么?
个人认为没区别 ,因为 handleClick 指向一个匿名函数,每次渲染都会生成一个新的函数引用,可以用 useCallback 来让 handleClick 指向的函数引用不变。 > 当用户点击 button 时,会触发“两”次 render,我不记得为什么了?是我记错了么? 刚在函数组件试了下,好像只触发了一次重渲染 ( React 17.0.2) |
5
mxT52CRuqR6o5 2021-06-24 20:13:39 +08:00 via Android
回调函数缓不缓存其实性能影响不大,useCallback 主要目的是缓存传给子组件的 render function,而且性能不是 react 设计的主要考量因素,react 自己那一套哲学才是设计主要考量因素
|
6
ChefIsAwesome 2021-06-24 20:41:55 +08:00
性能不能口头说,找个老手机一测便知。
|
7
sweetcola 2021-06-24 21:13:53 +08:00
> button1 和 button2 的用法,还有区别么?
没有区别。因为一旦渲染你写在外面和 onClick 里面都一样是动态生成的函数。 不过差别也有,就是非匿名函数和匿名函数的区别(也就是没什么区别)。 > 不过,当 handleClick 比较复杂时,应该可以通过 useCallback 提高性能 如果函数不影响重渲染的情况下用不用没有区别,甚至用了还会降低效率(依赖的比较)。因为就算你用了 useCallback,在重渲染的那一刻依然会生成一个函数,只是依赖没有变所以没有替换(以我理解)。 > 跟踪一下,触发了多少次 render ? 在组件里 console.log('Render'); 就可以了。 |
8
dany813 2021-06-25 11:19:42 +08:00
简单项目,就随便 render 了,想优化渲染就,useMemo 了
|
9
CodingNaux 2021-06-25 13:08:24 +08:00
- button 1,button 2 谁好?
没区别,又不是作为 props 传给子组件 - debug react devtool 里面就是性能分析,或者 console.log |
10
CodingNaux 2021-06-25 13:17:47 +08:00 1
|
11
DrakeXiang 2021-06-25 19:43:20 +08:00
https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-creating-functions-in-render
这里说之前对 inline function 的主要担心是会对子元素造成重复渲染,可以用 useCallback 这些来避免。重复创建函数并没有多大影响,不过我记得之前看到的文章说这种匿名的 inline 函数不光是会重复创建,而且因为是匿名的,创建之后只要页面存在就不会被垃圾回收,相当于内存泄漏,但是刚才搜了一下貌似都没看到这条。如果这条不成立的话那我觉得已经是没有影响的了 |
12
sheen 2021-06-26 01:15:33 +08:00
不让直接给 onClick 赋值一个匿名箭头函数的一个原因就是每次渲染都会重新生成一个新的函数,导致子组件里面的 PureComponent 或者 memo 失效了。
|
13
zhea55 2021-07-05 22:00:55 +08:00
|