面试题答案
一键面试功能区别
useCallback
:返回一个 memoized 回调函数。它的主要作用是确保在依赖项没有变化时,返回的回调函数引用保持不变。这有助于防止不必要的重新渲染,特别是在将回调函数作为 prop 传递给子组件时。useMemo
:返回一个 memoized 值。它会在其依赖项发生变化时重新计算 memoized 值。如果依赖项没有变化,就返回上一次计算的值,从而避免重复计算开销较大的操作。
使用场景区别
useCallback
:- 防止子组件不必要渲染:当把回调函数传递给子组件,而子组件依赖于回调函数的引用不变时使用。例如,子组件使用
React.memo
进行包裹,并且依赖于传入的回调函数来决定是否重新渲染。如果回调函数引用改变,即使子组件的其他 props 没有变化,也会触发重新渲染。 - 事件处理函数:在处理频繁触发的事件,如
onClick
、onChange
等,且该事件处理函数依赖一些 state 或 props 时,使用useCallback
可以避免每次渲染都创建新的函数。
- 防止子组件不必要渲染:当把回调函数传递给子组件,而子组件依赖于回调函数的引用不变时使用。例如,子组件使用
useMemo
:- 计算开销大的操作:当有复杂的计算逻辑,且该计算结果在依赖项未改变时不需要重新计算,如复杂的数组排序、过滤,对象的深度比较等。通过
useMemo
缓存计算结果,减少不必要的计算开销。 - 创建对象或数组:当需要在组件内部创建对象或数组,且依赖项未改变时不需要重新创建,使用
useMemo
可以避免每次渲染都创建新的对象或数组。
- 计算开销大的操作:当有复杂的计算逻辑,且该计算结果在依赖项未改变时不需要重新计算,如复杂的数组排序、过滤,对象的深度比较等。通过
示例
useCallback
示例
import React, { useState, useCallback } from 'react';
const ChildComponent = React.memo(({ onClick }) => {
console.log('ChildComponent rendered');
return <button onClick={onClick}>Click me</button>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<ChildComponent onClick={handleClick} />
</div>
);
};
export default ParentComponent;
在这个例子中,ChildComponent
使用了 React.memo
,如果 handleClick
函数不使用 useCallback
,每次 ParentComponent
渲染时都会创建新的 handleClick
函数,导致 ChildComponent
不必要的重新渲染。使用 useCallback
后,只有 count
变化时 handleClick
的引用才会改变,从而避免 ChildComponent
不必要的重新渲染。
useMemo
示例
import React, { useState, useMemo } from 'react';
const ExpensiveCalculation = ({ a, b }) => {
console.log('ExpensiveCalculation performed');
return a + b;
};
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [value, setValue] = useState(10);
const result = useMemo(() => {
return ExpensiveCalculation({ a: count, b: value });
}, [count, value]);
return (
<div>
<p>Count: {count}</p>
<p>Value: {value}</p>
<p>Result: {result}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<button onClick={() => setValue(value + 1)}>Increment Value</button>
</div>
);
};
export default ParentComponent;
在这个例子中,ExpensiveCalculation
模拟一个开销较大的计算函数。使用 useMemo
后,只有 count
或 value
变化时才会重新计算 result
,否则返回上一次计算的值,避免了不必要的计算。