How to optimize code with useCallback in React

In React, when the parent component is updated, what should the child component do?

First look at a piece of code, whether the child component will update when the parent component updates the state:

function Child(props){
    
    
  console.log('child更新')
  const {
    
    childName} = props
  return (
    <div>
      <h5>{
    
    childName}</h5>
      <button>changeChildName</button>
    </div>
  )
}

function Parent(){
    
    
  const [name,setName] = useState('farther')
  const [childName,setChildName] = useState('child')
  return (
    <div>
      <Child childName={
    
    childName} />
      <h4>{
    
    name}</h4>
      //更新name,父组件自己的状态
      <button onClick={
    
    () => {
    
    setName(Math.random())}}>changeFartherName</button>
    </div>
  )
}

In this example, the childName of the child component is obtained from the props of the parent component. But when I click the button, the state of the parent component is modified, and the props have not changed.
However, subcomponents are still updated. This is how React updates. But in this case, there is no need to re-render the subcomponents.

Based on the above situation, the memo method appeared.

React.memo

memo is a Hoc high-level component that can encapsulate components, and the encapsulated components will only render when props change.
For the above code, subcomponents can be encapsulated through memo:

 function getChild(props) {
    
    
  //父组件更新自己的状态时,不会render
  console.log("child更新");
  const {
    
     childName } = props;
  return (
    <div>
      <h5>{
    
    childName}</h5>
      <button>changeChildName</button>
    </div>
  );
}

const Child = memo(getChild);

function Parent() {
    
    
  const [name, setName] = useState("farther");
  const [childName, setChildName] = useState("child");
  return (
    <div>
      <Child childName={
    
    childName} setChildName={
    
    setChildName} />
      <h4>{
    
    name}</h4>
      <button
        onClick={
    
    () => {
    
    
          setName(Math.random());
        }}
      >
        changeFartherName
      </button>
    </div>
  );
}

By const Child = memo(getChild);wrapping the Child component, at this time, only when the childName property is changed, the child component will be updated.

React.memo also provides a second parameter, which receives a callback function, and the parameter is the old and new props. For example, you want to control under what conditions to update and under what conditions not to update. The update of the component is determined by the return value (true || false) of the method.

useCallback

For example, consider the following scenario. When the parent component passes the state value and the method of changing the state value to the child component. When the parent component is updated, is the method that the child component gets from props repeatedly defined, or is it always used?

 //用来存储父组件传给子组件的setChild方法
 let arr = [];
 function getChild(props) {
    
    
   console.log("child更新");
   const {
    
     childName, setChild } = props;
   arr.push(setChild);
   //判断每次传入的setChild方法是不是同一个
   if (arr.length > 1) {
    
    
     console.log(arr[0] === arr[1]); //false 答案不是同一个
   }
   return (
     <div>
       <h5>{
    
    childName}</h5>
       <button>changeChildName</button>
     </div>
   );
 }
 
 const Child = memo(getChild);
 
 function Parent() {
    
    
   const [name, setName] = useState("farther");
   const [childName, setChildName] = useState("child");
   //更改状态值的方法,传递给子组件
   const setChild = () => {
    
    
     if(Math.random() > 2){
    
    
       setChildName(Math.random())
     }
   }
   return (
     <div>
       <Child childName={
    
    childName} setChild={
    
    setChild} />
       <h4>{
    
    name}</h4>
       <button
         onClick={
    
    () => {
    
    
           setChildName(Math.random());
         }}
       >
         changeFartherName
       </button>
     </div>
   );
 }

Execute the above code, it can be seen that every time the parent component is updated, a setChild method must be defined. But it seems that this kind of repeated definition is not needed, so useCallback appears.

useCallback receives two parameters, the first parameter is the callback function, and the second parameter is an array. Returns a processed callback function.
It will only be updated if the dependencies in the array change. That is to say, the above code can be processed by useCallback:

  let arr = [];
  function getChild(props) {
    
    
    console.log("child更新");
    const {
    
     childName, setChild } = props;
    arr.push(setChild);
    if (arr.length > 1) {
    
    
      console.log(arr[0] === arr[1]); //true 说明拿到的方法都是一个方法的引用
    }
    return (
      <div>
        <h5>{
    
    childName}</h5>
        <button>changeChildName</button>
      </div>
    );
  }
  
  const Child = memo(getChild);
  
  function Parent() {
    
    
    const [name, setName] = useState("farther");
    const [childName, setChildName] = useState("child");
    //通过useCallback进行处理
    const setChild = useCallback(() => {
    
    
      if(Math.random() > 2){
    
    
        setChildName(Math.random())
      }
    },[])
    return (
      <div>
        <Child childName={
    
    childName} setChild={
    
    setChild} />
        <h4>{
    
    name}</h4>
        <button
          onClick={
    
    () => {
    
    
            setChildName(Math.random());
          }}
        >
          changeFartherName
        </button>
      </div>
    );
  }

And useCallback is a grammatical sugar of useMemo, so I won’t elaborate on the hook of useMemo here.

Guess you like

Origin blog.csdn.net/weixin_46726346/article/details/131126343