开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情
先上结论
- 如果想传递函数给子组件,请使用
useCallback
包裹后再传,避免子组件不必要的重复渲染,前提是子组件使用memo
函数包裹
- 如果想进行大量计算,请使用
useMemo
包裹计算逻辑后再使用其返回值,避免不必要的大量重复相同计算
- 如果想传递对象给子组件,请使用
useMemo
包裹后再传,避免子组件不必要的重复渲染,前提是子组件使用memo
函数包裹
问题:React
组件在state
和props
发生变化的时候都会从头到尾重新渲染一次,而在次渲染的时候,里面普通定义的函数、对象都会重新创建一次
一、useCallback
useCallback
实际目的是为了进行性能的优化,如何进行性能优化呢?
useCallback
会返回一个函数的memoized
记忆值,在依赖不变的情况下,多次定义的时候返回的值是相同的
const memoizedCallback = useCallback( () => {
doSomething(a, b)
}, [a, b])
对于定义一个函数本身来说,使用和不使用并不会带来性能优化,其优化的点在于,将把这个函数传递给子组件时,如果该函数不发生变化,那么子组件不会重新渲染!这就是性能优化的点,我们使用useCallback
的目的是不希望子组件进行多次渲染,并不是为了函数进行缓存。
二、useMemo
useMemo
实际目的是也为了进行性能的优化,如何进行性能优化呢?
useMemo
返回的也是一个 memoized
(记忆的)值,在依赖不变的情况下,多次定义的时候返回的值是相同的
const memoizedValue = useMemo( () => {
computeValue(a, b)
}, [a, b])
如果不使用useMemo
,在进行大量计算操作时,每次渲染组件都会重新计算一次,使用了useMemo
后,如果依赖不变,就不会重新计算!这就是优化的点,同时,对子组件传递相同内容的对象时,使用useMemo
也可以进行性能优化。
const info = useMemo( () => ({
name: 'coder',
age: 18
}))
// 传递给子组件,在父组件发生重新渲染时,子组件不会重新渲染
<Son info={info}/>
三、等价转换
从上面可以看出,如果useMemo
返回一个函数,那和useCallback
其实是一样的
useCallback(fn, deps)
和useMemo( ()=>fn, deps)
是等价的!
四、useRef
ueeRef
返回一个ref
对象,返回的Ref
对象在组件的整个生命周期保持不变
最常见的两种用法:
- 用法一:引入
DOM
(或者组件,但是需要是class组件)元素 - 用法二:保存一个数据,这个对象在整个生命周期中可以保持不变
该对象的值保存在current
属性中
绑定DOM
const titleRef = useRef()
// DOM保存在titleRef.current中
// 使用
<h1 ref={titleRef}>title</h1>
保存一个数据
使用其特性,对象在组件的整个生命周期内保持不变,可以结合useCallback
来使用,使用ref
对象来保存上一次的某一个下,下面保存的是当前的count
值
const App = memo( () => {
const [count, setCount] = useState(0)
const countRef Ref = useRef()
// 每次渲染的时候在这里获取最新的值
countRef.current = count
// 这里可以不添加依赖,这样传递给子组件不会引发子组件的更新
const increment = useCallback( () => {
setCurrent(countRef.current + 1)
},[])
})
感谢coderwhy老师的课程,收获良多。