在 React 组件的渲染过程中,useMemo 和 useEffect 的执行顺序是不同的。具体来说:
-
useMemo 先执行:useMemo 是在 渲染阶段 执行的,它的作用是缓存计算结果,确保在渲染过程中可以直接使用缓存的值。
-
useEffect 后执行:useEffect 是在 提交阶段 执行的,它的作用是处理副作用(如数据获取、DOM 操作等),并且是在 DOM 更新之后才运行。
详细执行顺序
- 组件渲染阶段:
-
React 调用组件的渲染方法(函数组件的函数体或类组件的 render 方法)。
-
在渲染过程中,useMemo 会被执行,计算并缓存值。
-
如果依赖项没有变化,useMemo 会直接返回缓存的值,避免重复计算。
- DOM 更新阶段:
- React 将组件的渲染结果应用到 DOM 上,更新 UI。
- 提交阶段:
-
在 DOM 更新完成后,React 会执行 useEffect 中的副作用函数。
-
如果 useEffect 有清理函数(返回的函数),它会在组件卸载或依赖项变化时执行。
示例代码
import React, { useMemo, useEffect, useState } from 'react';
function MyComponent({ a, b }) {
// useEffect 写在 useMemo 上面
useEffect(() => {
console.log('useEffect: Side effect after DOM update');
return () => {
console.log('useEffect: Cleanup');
};
}, [a, b]);
// useMemo 写在 useEffect 下面
const memoizedValue = useMemo(() => {
console.log('useMemo: Calculating expensive value...');
return a + b;
}, [a, b]);
console.log('Render: Component rendering...');
return (
<div>
<p>Memoized Value: {memoizedValue}</p>
</div>
);
}
function App() {
const [a, setA] = useState(1);
const [b, setB] = useState(2);
return (
<div>
<MyComponent a={a} b={b} />
<button onClick={() => setA(a + 1)}>Increment A</button>
<button onClick={() => setB(b + 1)}>Increment B</button>
</div>
);
}
控制台输出顺序
- 当组件首次渲染时:
Render: Component rendering...
useMemo: Calculating expensive value...
useEffect: Side effect after DOM update
- 当 a 或 b 变化时:
Render: Component rendering...
useMemo: Calculating expensive value...
useEffect: Cleanup
useEffect: Side effect after DOM update
总结
-
useMemo 在渲染阶段执行:无论它写在 useEffect 上面还是下面,它都会在组件渲染时执行。
-
useEffect 在提交阶段执行:它总是在 DOM 更新后执行,与代码书写顺序无关。
-
React 的执行顺序是固定的:useMemo 先执行,useEffect 后执行。
如果你需要在渲染阶段避免昂贵的计算,使用 useMemo;如果你需要在 DOM 更新后执行某些操作(如数据获取或订阅),使用 useEffect。