React - useMemo and useCallback hooks

 useMemo and useCallback hooks are introduced to optimize the performance of the application.

     Syntax:

            memoValue = useMemo(callback function, dependencies)

            memoCallback = useCallback(callback function, dependencies)


Note: If you didn't pass any dependencies then both hooks will return a new value every time.
           If you pass some dependencies, then it will return a new value whenever the dependency value changes.


1. useMemo:

          To understand this, consider the following example:

          const App = () =>{
                const [name, setName] = useState("");
                const [number, setNumber] = useState(1);
                const fact = factorial(number);

               function factorial(n){
                      console.log("factorial");
                      return n<=1?0:factorial(n-1);
               }
      
               return(
                     <>
                       <div>
                            <p>Hello {name}</p>
                            <input type="text" value={name} onChange ={e=> setName(e.target.value)}/>
                       </div>
                       <div>
                            <p>Factorial {fact}</p>
                            <input type="text" value={number} onChange ={e=> setNumber(e.target.value)}/>
                       </div>
                     </>
               );
          }

  

         If you run this and observe. you'll notice that if you are changing the name, factorial function executed even if we didn't change the value of number.

It is unnecessarily affecting the performance of the application by executing again and again. Hence to improve performance, we can use useMemo() hook by defining it as

              const fact = useMemo(()=> factorial(number), [number])


Update the code, and you'll see that factorial only runs when number state changes.


The most preferred way to use React.memo  is with functional components. If you want to prevent a component from re-rendering again and again, wrap it around React.memo while exporting it as

                  React.memo(functionalComponent)


Note: Here React checks the props. If the values and props are same, then the memoized result is reused and re-rendering is skipped.


2. useCallback:

           Before we understand useCallback, consider another scenario of using Memo:

      const App = () =>{
             const [number, setNumber] = useState(10);
             const [counter, setCounter] = useState(0);

           function random(){
                   return Math.random()*number+1;
           }

             return(
                  <>
                    <ChildComp num={number} />
                    <input type="text" value={number} onChange={e => setNumber(e.target.value)}/>
                    <div>
                           <p>Count: {counter}</p>
                          <button onClick={()=> setCounter(counter+1)}>Click</button>
                    </div>
                   </>
             );
      }


      ChildComp.js

       const ChildComp =(props) =>{
              console.log("Rendered");
              return(<p>Number: {props.num}</p>);
        }

        export default React.memo(ChildComp);


       Run this code and notice that ChildComp is not rendering when we increment the counter because of Memo.

Now instead of passing a single value, pass a function to child component as props and notice the change:

         Pass the random function as

               <ChildComp num= {random}>

         Now in return statement change props.num to props.num(), since we are passing a function now.


Now if you notice that even after applying memo, the whole component is re-rendering when we click on the button.

This is because memo compares the props, and here they are not same, that is why component gets rendered. 

To solve this problem we can use useCallback hooks to prevent re-rendering of child function. 

      Instead of passing the function as props pass it as a callback function as

     const memoCall = useCallback(random, [number])


     Pass this memoCall function instead of random() in ChildComp and you'll see that this time component will only render when we change the number state value and not on clicking the button.

        

Continue Learning: React useReducer





Comments

Popular Posts