Tìm hiểu về useMemo và useCallback trong NextJs

1. useMemo
useMemo nó nằm trong collections hooks của Reactjs được bổ sung ở version 16.8, nói đến hooks thì các bạn hay sử dụng phổ biến như useState, useEffect, còn nâng cao hơn tí là useMemo.
useMemo là một hàm, hàm này có tác dụng giúp cải thiện performance của app tốt hơn. Đầu vào của useMemo gồm hai tham số đó là function và một list dependencies.
useMemo sẽ lưu giá trị trả về của function và đem nó đi so sánh với dependencies, nếu dependencies thay đổi thì nó mới chạy các hàm phía trong còn nếu dependencies không thay đổi thì nó sẽ trả về value đã cached trước đó

    import React, {useState} from 'react';
    function App() {
          const [length, set_length] = useState(3);
          const [name, set_name] = useState('John Doe');

   return (
      <>
      <input value={name} onChange={e => set_name(e.target.value)} />
      <NameDisplay name={name}/>
      <hr />
      <input value={length} onChange={e => set_length(Number(e.target.value))} />
      <FibDisplay length={length} />
    </>
      );
    }

    function FibDisplay({length}) {
      console.log('Calculating numbers & rerendering...');
      const numbers = [1, 1];
      for (let i = 2; i < length; i++) {
        numbers[i] = numbers[i - 1] + numbers[i - 2];
      }

      return <p>{length} numbers of the fibonacci sequence: {numbers.join(', ')}</p>;
    }
        export default App;

Bạn có thể thấy hàm FibDisplay chỉ rerender khi length thay đổi thôi
Khi nào nên sử dụng useMemouseMemo giúp performance của app trở nên rất tốt nhưng cũng đừng vì điều đó mà lạm dụng nó quá. Chỉ sử dụng khi những really expensive computation thôi.

2. useCallback
useCallback được sử dụng để tối ưu quá trình render của React functional components. Nó sẽ rất hữu ích đối với trường hợp một thành phần (component) liên tục được hiển thị lại không cần thiết trong quá trình xử lý sự kiện người dùng và có hành vi chức năng phức tạp.

    import React, { useState, useCallback } from 'react'

    function Counter() {
        const [count, setCount] = useState(0);
        const [countOther, setCountOther] = useState(0);

        const increase = () => setCount(count + 1);
        const decrease = () => setCount(count - 1);

        const increaseOther = () => setCountOther(countOther + 1);
        const decreaseOther = () => setCountOther(countOther + 1);

    return (
            <>
                <div>Count: {count}</div>
                <button onClick={increase}>+</button>
                <button onClick={increase}>-</button>

                <div>Count other: {countOther}</div>
                <button onClick={increaseOther}>+</button>
                <button onClick={decreaseOther}>-</button>
            </>
    )
    }

    export default Counter;

Điều này khá đơn giản, chúng ta có biến 2 state nắm giữ số đếm và 4 hàm để thay đổi con số của 2 state trên. Tuy nhiên, vấn đề ở đây là mỗi lần thành phần Counter này re-render, tất cả 4 hàm, increase, decrease, increaseOther, decreaseOther sẽ bị khởi tạo lại

Chúng ta có thể thấy điều đó bằng cách sử dụng Set và thêm các hàm vào bên trong Set mỗi lần Counter re-render. Tại sao lại là Set. Đây là đối tượng lưu trữ phần tử có tính duy nhất, không trùng lặp.

    import React, { useState, useCallback } from 'react'

    const storeSet = new Set(); 

    function Counter() {
        const [count, setCount] = useState(0);
        const [countOther, setCountOther] = useState(0);
        const increase = () => setCount(count + 1);
        const decrease = () => setCount(count - 1);

        const increaseOther = () => setCountOther(countOther + 1);
        const decreaseOther = () => setCountOther(countOther + 1);

        storeSet.add(increase);
        storeSet.add(decrease);
        storeSet.add(increaseOther);
        storeSet.add(decreaseOther);

        console.log(storeSet);

    return (
            <>
                <div>Count: {count}</div>
                <button onClick={increase}>+</button>
                <button onClick={increase}>-</button>

                <div>Count other: {countOther}</div>
                <button onClick={increaseOther}>+</button>
                <button onClick={decreaseOther}>-</button>
            </>
    )
    }

    export default Counter;

Nào, bây giờ cùng kiểm tra thử nhé?. Mỗi lần bạn click vào bất kì nút tăng giảm sẽ thấy hiển thị giá trị của storeSet. Bạn sẽ thấy chúng tăng giá trị mỗi lần hiển thị, điều này cho thấy mỗi lần thành phần re-render sẽ tạo ra phiên bản hoàn toàn mới của các hạm được tạo ra.

3. Sự khác nhau giữa useMemo và useCallback

  • useMemo giữ cho một hàm không được thực thi lại nếu nó không nhận được một tập hợp các tham số đã được sử dụng trước đó. Nó sẽ trả về kết quả của một function. Sử dụng nó khi bạn muốn ngăn một số thao tác nặng hoặc tốn kém tài nguyên được gọi trên mỗi lần render.

  • useCallback giữ cho một hàm không được tạo lại lần nữa, dựa trên mảng các phần phụ thuộc. Nó sẽ trả về chính function đó. Sử dụng nó khi mà bạn muốn truyền fuction vào component con và chặn không cho một hàm nào đó tiêu thời gian, tài nguyên phải tạo lại.

4.Tài liệu tham khảo
https://reactjs.org/docs/hooks-reference.html#usememo
https://reactjs.org/docs/hooks-reference.html#usecallback
https://viblo.asia/p/react-hooks-su-khac-nhau-giua-usememo-va-usecallback-gDVK24jwlLj?fbclid=IwAR3ZudxEi7wAHkh-jzsQf9-oawJwoj1vZhhxlIeeFld4LC2r4qUBUPWTkes