react icon indicating copy to clipboard operation
react copied to clipboard

New hook: useMemoWithPrev

Open bambalic opened this issue 1 year ago • 2 comments

Sometimes you may need access to previous/last value of useMemo hook. Something similar is available when we set state (useState hook).

Some use case would be:

// current useMemo
const memoValueWithUseMemo = useMemo(() => {
  const shouldGetReevaluated = someExpensiveOperation(dep1, dep2, dep3);
  const otherStuff1 = getOtherStuff1(dep1);
  const otherStuff2 = getOtherStuff2(dep2);
  const otherStuffN = getOtherStuffN(dep3);

  return { shouldGetReevaluated, otherStuff1, otherStuff2, otherStuffN };
}, [dep1, dep2, dep3]);

I am suggesting something like this:

const memoValueWithUseMemoWithPrev = useMemoWithPrev(
  (prev) => () => {
    // additional prev value is available
    // evade expensive operation
    if (prev.shouldGetReevaluated) {
      return prev;
    }
    const shouldGetReevaluated = someExpensiveOperation(dep1, dep2, dep3);

    const otherStuff1 = getOtherStuff1(dep1);
    const otherStuff2 = getOtherStuff2(dep2);
    const otherStuffN = getOtherStuffN(dep3);

    return { shouldGetReevaluated, otherStuff1, otherStuff2, otherStuffN };
  },
  [dep1, dep2, dep3],
);

The hook itself would be something like this:


const useMemoWithPrev = (calculateValueFunction, dependencies) => {
    const prev = useRef({});

    const memoValue = useMemo(calculateValueFunction(prev.current), dependencies || []);
    prev.current = memoValue;
    return memoValue;
  };

Difference is that we would need to pass function that returns function, but that's it. It probably couldn't be done by updating current useMemo because useMemo can be used to memoize higher order functions, so difference in callback we pass to it cannot determine whether we want to use it with previous value or not.

If we have this we could skip even more calculations than we are already skipping with useMemo.

Yes, this can be done by adding the same thing to our code, but it would be cool to have this in react.

bambalic avatar Feb 27 '24 22:02 bambalic

I think this hook should be something implemented outside React since usage of this custom hook feels like is niche case and since it looks like it is possible to implement this custom hook without any changes to the React itself.

ZilvinasAbr avatar Mar 01 '24 11:03 ZilvinasAbr

usage of this custom hook feels like is niche case

Disagree. Usage of such a hook is a requisite for those cases where Object.is can not carry the necessary equality semantics for a memo'd computation. You'll already run head-first into the mess this involves when you start using Date or any of the many date-handling library solutions out there.

Moreover, as useMemo currently takes a parameterless function, it can be extended to give back the previous memo'd value gracefully, without breaking existing applications.

rjgotten avatar May 15 '24 15:05 rjgotten

I'm not sure how this suggestion would also work out with soon-to-be-released React Compiler: essentially usages of useMemo in probably most cases will not be necessary.

ZilvinasAbr avatar Aug 08 '24 09:08 ZilvinasAbr