简体   繁体   English

useMemo 与 useEffect + useState

[英]useMemo vs. useEffect + useState

Are there any benefits in using useMemo (eg for an intensive function call) instead of using a combination of useEffect and useState ?使用useMemo (例如用于密集函数调用)而不是使用useEffectuseState的组合有useEffect useState

Here are two custom hooks that work exactly the same on first sight, besides useMemo 's return value being null on the first render:这里有两个自定义钩子,乍一看完全相同,除了useMemo的返回值在第一次渲染时为null

在 CodeSandbox 上查看

useEffect & useState useEffect & useState

import { expensiveCalculation } from "foo";

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

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

  return result;
}

useMemo使用备忘录

import { expensiveCalculation } from "foo";

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

Both calculate the result each time their parameter someNumber changes, where is the memoization of useMemo kicking in?每次他们的参数someNumber改变时,两者都会计算结果, useMemo的记忆在哪里开始?

The useEffect and setState will cause extra renders on every change: the first render will "lag behind" with stale data and then it'll immediately queue up an additional render with the new data. useEffectsetState将在每次更改时导致额外的渲染:第一个渲染将“滞后”与陈旧数据,然后它将立即使用新数据排队附加渲染。


Suppose we have:假设我们有:

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

Lets suppose someNumber is initially 0:让我们假设someNumber最初是 0:

  • The useMemo version immediately renders 1 . useMemo版本立即呈现1
  • The useEffect version renders null , then after the component renders the effect runs, changes the state, and queues up a new render with 1 . useEffect版本渲染null ,然后在组件渲染效果后运行,更改状态,并使用1将新渲染排队。

Then if we change someNumber to 2:然后,如果我们将someNumber更改为 2:

  • The useMemo runs and 3 is rendered. useMemo运行并呈现3
  • The useEffect version runs, and renders 1 again, then the effect triggers and the component reruns with the correct value of 3 . useEffect版本运行,并再次渲染1 ,然后触发效果并且组件以正确的3值重新运行。

In terms of how often expensiveCalculation runs, the two have identical behavior, but the useEffect version is causing twice as much rendering which is bad for performance for other reasons.expensiveCalculation运行的频率而言,两者具有相同的行为,但useEffect版本导致两倍的渲染,这对性能不利,因为其他原因。

Plus, the useMemo version is just cleaner and more readable, IMO.另外,IMO 的useMemo版本更清晰、更易读。 It doesn't introduce unnecessary mutable state and has fewer moving parts.它不会引入不必要的可变状态并且具有更少的移动部件。

So you're better off just using useMemo here.所以你最好在这里使用useMemo

I think there are two main points you should consider when choosing between them.我认为在它们之间进行选择时,您应该考虑两个要点。

  1. Time when function called.函数调用的时间。

useEffect called after component has been rendered, so you can access DOM from it. useEffect在组件渲染后调用,因此您可以从中访问 DOM。 For example, this is important if you want to access DOM elements via refs.例如,如果您想通过 refs 访问 DOM 元素,这很重要。

  1. Semantic guarantees.语义保证。

useEffect guarantees that it will not be fired if dependencies have not changed. useEffect保证在依赖项没有改变的情况下它不会被触发。 useMemo does not give such guarantees. useMemo不提供此类保证。

As stated in the React documentation , you should consider useMemo as pure optimization technique.React 文档中所述,您应该将 useMemo 视为纯优化技术。 Your program should continue to work correctly even if you replace useMemo with regular function call.即使您用常规函数调用替换 useMemo,您的程序也应该继续正常工作。

useEffect + useState can be used to control updates. useEffect + useState可用于控制更新。 Even to break-up circular dependencies and prevent infinite update loops.甚至打破循环依赖并防止无限更新循环。

I would say other than the async nature, there might be some difference in terms how they are designed.我想说除了异步性质之外,它们的设计方式可能存在一些差异。

useEffect is a collective call, async or not, it's collected after all components are rendered. useEffect是一个集体调用,无论异步与否,它都是在所有组件渲染后收集的。

useMemo is a local call, it only have something to do with this component. useMemo是一个本地调用,它只与这个组件有关。 You could just think of useMemo as another assignment statement with benefits to skip assignment sometimes.您可以将useMemo视为另一个赋值语句,有时可以跳过赋值语句。

Which means, useMemo is more urgent, then useLayoutEffect and the last being useEffect , especially when the input is from a prop.这意味着, useMemo是更为迫切,然后useLayoutEffect和最后被useEffect ,特别是当输入是来自一个道具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM