6

React: How does useMemo and useCallback work ?

 1 year ago
source link: https://dev.to/linhbui167/react-how-does-usememo-and-usecallback-work--4e0d
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

How does useMemo and useCallback work ?

When render a component, React will process the whole Component code. There might be several computed values and functions that its values only depends on few dependencies and does not need to re-calculate everytime.

If these values require a lot of time to calculate, it will let the render process down as consequent.

In order to improve performance, React produce useMemo and useCallback.
Implement it quite simple:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

The way it work are similar to each other and quite easy to understand.

💥 All the code reference I mentioned in this article was translated to javascriptand cut-off **comments* and warning parts just for shorter code and more clear.

Click View Source to see the original code*

1.Mount Phase (First Render)

function mountMemo(nextCreate, deps){
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

View Source

function mountCallback(callback, deps){
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

View Source

When component was rendered on first time, useMemo will execute the create function (nextCreate) to get return value and then store the value and dependency list into memoizedState, meanwhile useCallback store all of its inputs.

2.Update Phase

function updateMemo(nextCreate, deps) {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

View Source

function updateCallback(callback, deps) {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

View Source

When re-render a component, useMemo and useCallback will compare old dependency (that was already memoized) with the new one.

If one of those are null or they are difference (result from areHookInputsEqual), useMemo and useCallback will store and return the new value.

Otherwise, return memoized value.

Compare hook dependency function

function areHookInputsEqual(nextDeps, prevDeps) {
  if (prevDeps === null) {
    return false;
  }
  for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
    if (is(nextDeps[i], prevDeps[i])) {
      continue;
    }
    return false;
  }
  return true;
}

View Source

React will use Object.is to compare previos and next value of dependency. You may find the difference of its behavior here.

function is(x, y) {
  return (
    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
  );
}
const objectIs = typeof Object.is === 'function' ? Object.is : is;
export default objectIs;

View Source

🎉 As React announcement in July 2022, there might be a new Compiler that auto generate useMemo and useCallback for us.

You can read this post here: https://reactjs.org/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK