preface

When developing React, we often encounter the situation that the parent component introduces the child component. When no optimization is done, the child component is often rendered unnecessarily repeatedly. Look at a simple example

Example 1: In this case, every time the parent updates the count value, the child component repeats the rendering

function Child(props){
    console.log('Subcomponent Render')
    return(
        <div>{props.title}</div>)}function Parent(){
    const [count, setCount] = useState(1);
    return(
        <div>
            <Child title="I am a child component" />
            <button onClick={()= > setCount(count+1)}>add</button>
            <div>count:{count}</div>
        </div>)}Copy the code

React.memo

React.memo is a higher-order component, which is similar to the react. PureComponent

React.memo(component, Func), the first argument is a custom component, and the second argument is a function to determine if the component needs to be re-rendered. If the second parameter is omitted, the default is a shallow comparison of the props of the component

// Modify example 1: In this case, the props of the Child are not changed, so the render is not repeated
function Child(props){
    console.log('Subcomponent Render')
    return(
        <div>{props.title}</div>)}const NewChild = React.memo(Child, (prevProps, nextProps) = > {
      // A custom comparison method can also be ignored
      // return true does not re-render
      // return false to re-render
})
function Parent(){
    const [count, setCount] = useState(1);
    return(
        <div>
            <NewChild title="I am a child component" />
            <button onClick={()= > setCount(count+1)}>add</button>
            <div>count:{count}</div>
        </div>)}Copy the code

However, in some cases, the react. Memo is wrapped around the subcomponents, and the subcomponents still do unnecessary repeated rendering updates, where useMemo and useCallback can be used for more granular performance optimization. Look at this example

2 / / examples
function Child({title, onChangeTitle}){
  console.log('Subcomponent Render')
  return(
      <>
        <div>{title.value}</div>
        <button onClick={()= >OnChangeTitle (' I am the new title')}>change title</button>
      </>)}constNewChild = React. Memo (Child);function Parent(){
    const [count, setCount] = useState(1);
    const [title, setTitle] = useState('I'm a child component');
    const onChangeTitle = (text) = > {
        setTitle(text)
    }
    return(
        <div>
            <NewChild title={{value: title}} onChangeTitle={onChangeTitle}>
            <button onClick={()= > setCount(count+1)}>add</button>
            <div>count:{count}</div>
        </div>)}Copy the code

In this case, each time the parent component updates, the title and onChangeTitle values of the child component generate a new memory address, so even if the title does not change, the child component is rerendered, and the memo is invalid

useMemo

Executed on the first rendering, the variables are cached and then recalculated only when the dependency changes

useCallback

The function is cached the first time it is rendered, and then the cache is updated only when a dependency changes

// modify example 2
function Child({title, onChangeTitle}){
  console.log('Subcomponent Render')
  return(
      <>
        <div>{title.value}</div>
        <button onClick={()= >OnChangeTitle (' I am the new title')}>change title</button>
      </>)}constNewChild = React. Memo (Child);function Parent(){
  const [count, setCount] = useState(1);
  const [title, setTitle] = useState('I'm a child component');
  const onChangeTitle = useCallback((text) = > {
      setTitle(text)
  },[])
  const memoTitle = useMemo(() = > ({value: title}), [title])
  return(
      <div>
          <NewChild title={memoTitle} onChangeTitle={onChangeTitle} />
          <button onClick={()= > setCount(count+1)}>add</button>
          <div>count:{count}</div>
      </div>)}Copy the code

conclusion

UseMemo and useCallback are used in the same way. They are both executed on the first rendering and again when a dependency changes. The difference is that useMemo returns cached variables and useCallback returns cached functions

In the actual business component development process, it will be much more complex than the above example, so there will be many factors that cause unnecessary repeated rendering. We need to use React. Memo, useMemo, and useCallback to optimize the components, but do not blindly use them