Hook useMemo giúp ta lưu lại kết quả của các tác vụ tính toán giữa những lần re-render nhằm cải thiện hiệu năng của chương trình.

const cachedValue = useMemo(calculateValue, dependencies)

Context

Sử dụng useMemo khi kết quả đầu vào cố định của một hàm nào đó luôn cho ra giá trị không đổi.

Ta sẽ viết một hàm mô phỏng lại một tác vụ tính toán phức tạp và cần nhiều thời gian như sau:

function expensiveCalculation(number) {
  const start = new Date()
 
  while (new Date() - start < 2000);
 
  return number * number
}

Hàm expensiveCalculation ở trên sẽ mất 2 giây để thực thi.

Ta gọi sử dụng hàm expensiveCalculation bên trong component App như bên dưới:

import { useState } from "react"
 
function App() {
  const [count, setCount] = useState(0)
 
  const result = expensiveCalculation(10)
 
  return (
    <>
      <p>Count: {count}</p>
      <p>Result: {result}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  )
}
 
export default App

Bất cứ khi nào ta bấm nút và làm thay đổi giá trị của biến count, component sẽ được re-render. Ở mỗi lần re-render, hàm expensiveCalculation sẽ được thực thi lại.

Có thể thấy, đối số của expensiveCalculation là một hằng số không đổi, dẫn đến giá trị của result cũng không đổi. Vì vậy, việc tái thực thi hàm expensiveCalculation là không cần thiết.

Usage

Ta ngăn chặn sự tái thực thi hàm expensiveCalculation bằng hook useMemo như sau:

import { useState, useMemo } from "react"
 
function App() {
  const [count, setCount] = useState(0)
 
  const result = useMemo(() => {
    return expensiveCalculation(10)
  }, [])
 
  return (
    <>
      <p>Count: {count}</p>
      <p>Result: {result}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  )
}
 
export default App

Giải thích đoạn code trên:

  • Hàm useMemo sẽ nhận vào hai đối số. Đối số đầu tiên là một hàm giúp thực hiện các tác vụ tính toán, ta gọi hàm này là calculateValue. Hàm calculateValue không nên sử dụng tham số và nên trả về một giá trị nào đó.
  • Đối số thứ hai là dependency array, có chức năng tương tự như useEffect: nếu các phần tử trong dependency array thay đổi thì calculateValue sẽ được tái thực thi.

Trong ví dụ trên, ta sử dụng dependency array là một mảng rỗng vì ta chỉ muốn thực thi expensiveCalculation một lần duy nhất.

Giả sử đối số của expensiveCalculation là một reactive value. Khi đó, ta cần phải liệt kê giá trị này ở bên trong dependency array như sau:

import { useState, useMemo } from "react"
 
function App() {
  const [count, setCount] = useState(0)
  const [number, setNumber] = useState(10)
 
  const result = useMemo(() => {
    return expensiveCalculation(number)
  }, [number])
 
  return (
    <>
      <p>Count: {count}</p>
      <p>Result: {result}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  )
}
 
export default App

Resources