react 16.8 版本引入 Hook 特性,可以让开发者在不编写 class 组件的情况下,在函数式组件内部使用 state 及其它特性;函数式组件也不再是单单的无状态组件,可以进行副作用等操作。Hook 给予开发者抽取组件复用状态逻辑多了一种方式。
Hook 的引进是令人兴奋的,同时也给予了习惯使用生命周期的部分开发者(菜鸟正是在下)一定的心智负担;下面是个人对 useCallback
和 useMemo
两个 Hook 的简单了解。
useCallback
- 接收两个参数;第一个参数为回调函数,第二个参数为依赖项数组,返回一个被缓存过的函数;
- 依赖项数组,控制回调函数是否重新更新的关键;数组元素一般为回调函数的形参;
- 把缓存过的函数传递于使用引用相等性的子组件时,避免不必要的渲染。
function App() {
const [count, updateCount] = useState(0)
const handleChild = useCallback(() => {
//TODO: do something
doSomething(a, b)
}, [a, b])
return (
<div className="App">
<button onClick={() => updateCount(count + 1)}>updateCount</button>
<p>{count}</p>
<Children do={handleChild} />
</div>
)
}
// memo 实现了函数式组件中的 shouldCompoentUpdate
export default memo(function Children () {
console.log('re render')
return <div>children</div>
})
子组件在使用 memo
包裹的情况下,父组件使用 useCallback
用于控制子组件不必要的渲染。
useMemo
- 接收两个参数;第一个参数为回调函数(需要返回值),第二个参数为依赖项数组,返回一个被缓存过的值;
- 避免组件在每次渲染时都进行高开销计算的优化的策略。
function App() {
const [count, updateCount] = useState(0)
const [num, updateNum] = useState(0)
function expensive (count) {
// 模拟高开销计算
console.log('render')
const array = new Array(count).fill(count);
return array.reduce((currentTotal, item) => {
return currentTotal + item;
}, 0)
}
const count_memoized = useMemo(() => expensive(count), [count])
// const _count = expensive(count)
return (
<div className="App">
<button onClick={() => updateCount(count + 1)}>updateCount</button>
<button onClick={() => updateNum(num + Math.random())}>updateNum</button>
<p>{count_memoized}</p>
</div>
)
}
未使用 useMemo
时,每次调用 updateNum
会导致 expensive
函数的调用;使用 useMemo
后,当依赖项 count
改变时,才会去调用 expensive
函数。