UseMemo vs useEffect 和 useState

使用 useMemo(例如对于密集的函数调用)而不是使用 useEffectuseState的组合有什么好处吗?

这里有两个自定义的钩子,工作完全相同的第一眼,除了 useMemo的返回值是 null的第一次渲染:

See on CodeSandbox

使用效果和使用状态

import { expensiveCalculation } from "foo";


function useCalculate(someNumber: number): number | null {
const [result, setResult] = useState(null);


useEffect(() => {
setResult(expensiveCalculation(someNumber));
}, [someNumber]);


return result;
}

用备忘录

import { expensiveCalculation } from "foo";


function useCalculateWithMemo(someNumber: number): number {
return useMemo(() => {
return expensiveCalculation(someNumber);
}, [someNumber]);
};

每次他们的参数 someNumber变化时,他们都会计算结果,那么 useMemo的制表在哪里起作用呢?

96430 次浏览

useEffectsetState在每次更改时都会导致额外的呈现: 第一次呈现将“滞后”于过期数据,然后它将立即用新数据排队等待额外的呈现。


假设我们有:

// Maybe I'm running this on a literal potato
function expensiveCalculation(x) { return x + 1; };

假设 x最初为0:

  • useMemo版本立即呈现 1
  • useEffect版本呈现 null,然后在组件呈现效果运行之后,更改状态,并使用 1排队进行新的呈现。

如果我们把 x改成2:

  • 运行 useMemo并呈现 3
  • useEffect版本运行,并再次呈现 1,然后效果触发器和组件以正确的 3值重新运行。

expensiveCalculation的运行频率而言,两者具有相同的行为,但是 useEffect版本导致了两倍的呈现,这对性能有其他原因的影响。

另外,useMemo版本只是更干净,更易读,IMO。它不会引入不必要的可变状态,并且运动部件较少。

所以你最好在这里使用 useMemo

我认为有两个要点,你应该考虑在他们之间作出选择。

  1. 函数调用的时间。

在呈现组件之后调用的 useEffect,因此可以从中访问 DOM。例如,如果希望通过参考文献访问 DOM 元素,这一点就很重要。

  1. 语义保证。

useEffect保证,如果依赖项没有更改,它将不会被触发。 useMemo不提供这样的保证。

反应文件中所述,您应该将 useMemo 视为纯粹的优化技术。即使用常规函数调用替换了 useMemo,程序也应该能够正常工作。

useEffect + useState可以用来控制更新。甚至可以打破循环依赖,防止无限更新循环。

我想说的是,除了异步性质之外,它们的设计方式可能会有一些不同。

useEffect是一个集合调用,无论是否异步,它都是在所有组件呈现之后收集的。

useMemo是一个本地调用,它只与这个组件有关。您可以将 useMemo看作是另一个赋值语句,利用上次更新中的赋值可以从中受益。

这意味着,useMemo更紧急,然后是 useLayoutEffect,最后是 useEffect