useMemo vs. useEffect + useState

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

下面是两个自定义钩子,它们在第一次呈现时的工作方式完全相同,此外,返回值还在第一次渲染上:useMemonull

See on CodeSandbox

useEffect & useState

import { expensiveCalculation } from "foo";

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

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

  return result;
}

使用备忘录

import { expensiveCalculation } from "foo";

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

每次参数变化时,两者都计算结果,踢入的记忆在哪里?someNumberuseMemo


答案 1

和 将在每次更改时导致额外的渲染:第一个渲染将使用陈旧数据“滞后”,然后它会立即将其他渲染与新数据排队。useEffectsetState


假设我们有:

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

假设最初是 0:x

  • 版本会立即呈现 。useMemo1
  • 版本呈现 ,然后在组件呈现效果运行后,更改状态,并使用 将新呈现排入队列。useEffectnull1

然后,如果我们更改为 2:x

  • 运行并呈现。useMemo3
  • 版本运行并再次渲染,然后触发效果,组件以正确的值重新运行。useEffect13

就运行频率而言,两者具有相同的行为,但版本导致渲染量增加一倍,由于其他原因,这对性能不利。expensiveCalculationuseEffect

另外,该版本更干净,更具可读性,IMO。它不会引入不必要的可变状态,并且具有较少的活动部件。useMemo

所以你最好只在这里使用。useMemo


答案 2

我认为在它们之间进行选择时,您应该考虑两个要点。

  1. 调用函数的时间。

useEffect在组件呈现后调用,以便您可以从中访问 DOM。例如,如果要通过引用访问 DOM 元素,这一点很重要。

  1. 语义保证。

useEffect保证在依赖项未更改时不会触发它。 不提供此类保证。useMemo

React 文档中所述,您应该考虑使用 Memo 作为纯优化技术。即使您将 useMemo 替换为常规函数调用,您的程序也应继续正常工作。

useEffect + useState可用于控制更新。甚至可以打破循环依赖关系并防止无限更新循环。