useCallback
和 useMemo
结合 React.Memo
方法的使用是常见的性能优化方式,可以避免由于父组件状态变更导致不必要的子组件进行重新渲染
useCallback
useCallback
用于创建返回一个回调函数,该回调函数只会在某个依赖项发生改变时才会更新,可以把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染的子组件,在 props 属性相同情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果
import React, { useState, useCallback } from 'react';
function SubmitButton(props) {
const { onButtonClick, children } = props;
console.log(`${children} updated`);
return (
<button onClick={onButtonClick}>{children}</button>
);
}
// 使用 React.memo 检查 props 变更,复用最近一次渲染结果
SubmitButton = React.memo(submitButton);
export default function CallbackForm() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const handleAdd1 = () => {
setCount1(count1 + 1);
}
// 调用 useCallback 返回一个 memoized 回调,该回调在依赖项更新时才会更新
const handleAdd2 = useCallback(() => {
setCount2(count2 + 1);
}, [count2]);
return (
<>
<div>
<p>count1: {count1}</p>
<SubmitButton onButtonClick={handleAdd1}>button1</SubmitButton>
</div>
<div>
<p>count2: {count2}</p>
<SubmitButton onButtonClick={handleAdd2}>button2</SubmitButton>
</div>
</>
)
}
useCallback(fn, deps)
相当于 useMemo(() => fn, deps)
,以上 useCallback
可替换成 useMemo
结果如下:
const handleAdd2 = useMemo(() => {
return () => setCount2(count2 + 1);
}, [count2]);
useMemo
把"创建"函数和依赖项数组作为参数传入 useMemo
,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算
使用注意:
-
传入
useMemo
的函数会在渲染期间执行,不要在这个函数内部执行与渲染无关的操作 -
如果没有提供依赖项数组,
useMemo
在每次渲染时都会计算新的值import React, { useState, useMemo } from 'react';
function counterText({ countInfo }) {
console.log(${countInfo.name} updated
);return ( <p>{countInfo.name}: {countInfo.number}</p> );
}
// // 使用 React.memo 检查 props 变更,复用最近一次渲染结果
const CounterText = React.memo(counterText);export default function Counter() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);const countInfo1 = { name: 'count1', number: count1 }; // 使用 useMemo 缓存最近一次计算结果,会在依赖项改变时才重新计算 const countInfo2 = useMemo(() => ({ name: 'count2', number: count2 }), [count2]); return ( <> <div> <CounterText countInfo={countInfo1} /> <button onClick={() => setCount1(count1 + 1)}>Add count1</button> </div> <div> <CounterText countInfo={countInfo2} /> <button onClick={() => setCount2(count2 + 1)}>Add count2</button> </div> </> );
}