useCallback memory function and useMemo memory component

Posted by mpf on Tue, 11 Jan 2022 01:49:59 +0100

useCallback memory function

In class components, we often make the following mistakes:

class App {
    render() {
        return <div>
            <SomeComponent
              style={{ fontSize: 14 }}
              doSomething={ () => ​{
                console.log('do something');
              }}
            />
        </div>;
    }
}

What's the harm of writing like this? Once the props or state of the App component changes, it will trigger re rendering. Even if it is not related to the SomeComponent component, because each render will generate new style and doSomething (because style and doSomething point to different references before and after re rendering), it will cause the SomeComponent to re render, If SomeComponent is a large component tree, the comparison of Virtual Dom is obviously wasteful, and the solution is very simple. Extract the parameters into variables.

const fontSizeStyle = { fontSize: 14 };
class App {
    doSomething = () => {
        console.log('do something');
    }
    render() {
        return <div>
            <SomeComponent
              style={fontSizeStyle}
              doSomething={
                this.doSomething
              }
            />
        </div>;
    }
}

In class components, we can also store functions through this object, but we can't mount them in function components. Therefore, function components will re render sub components if there is a transfer function during each rendering.

​function App() {
  const handleClick = () => {
    console.log('Click happened');
  }
  return <SomeComponent onClick={handleClick}>Click Me</SomeComponent>;
}

Because the functional component is understood as the syntax sugar of the class component render function, every time you re render, all the code inside the functional component will be re executed. Therefore, each render and handleClick in the above code will be a new reference, that is, the props passed to the SomeComponent component Onclick is always changing (because it is a new reference every time), so it is said that in this case, the function component will re render the sub component if there is a transfer function during each rendering.

With useCallback, you can get a memorized function through useCallback.

function App() {
  const memoizedHandleClick = useCallback(() => {
    console.log('Click happened')
  }, []); // An empty array means that the function will not change under any circumstances
  return <SomeComponent onClick={memoizedHandleClick}>Click Me</SomeComponent>;
}

The second parameter is passed into an array. Once the value or reference of each item in the array changes, useCallback will return a new memory function for later rendering.

In this way, as long as the child component inherits PureComponent or uses react Memo can effectively avoid unnecessary VDOM rendering.

useMemo memory assembly

The function of useCallback can be completely replaced by useMemo. If you want to return a memory function by using useMemo @, it is also completely possible.

useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs))

Therefore, the previous example using useCallback can be rewritten using useMemo:

function App() {
  const memoizedHandleClick = useMemo(() => () => {
    console.log('Click happened')
  }, []); // An empty array means that the function will not change under any circumstances
  return <SomeComponent onClick={memoizedHandleClick}>Click Me</SomeComponent>;
}

The only difference is that useCallback does not execute the first parameter function, but returns it to you, while useMemo executes the first function and returns the result to you. Therefore, in the previous example, you can return handleClick to store the function.

Therefore, useCallback often remembers event functions, generates memorized event functions and passes them to sub components for use. useMemo is more suitable for obtaining a certain value through function calculation, such as memory components.

function Parent({ a, b }) {
  // Only re-rendered if `a` changes:
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // Only re-rendered if `b` changes:
  const child2 = useMemo(() => <Child2 b={b} />, [b]);
  return (
    <>
      {child1}
      {child2}
    </>
  )
}

child1/child2 will re render when a/b changes. As can be seen from the example, the update of the sub component is triggered only when the value of the second parameter array changes.

Pay attention to me. In the next section, we will learn useRef saving reference values and useImperativeHandle transparent Ref.

Topics: Javascript React