Tự học ReactJS: React Performance – Sử dụng useMemo để tối ưu cho những tính toán phức tạp

Tự học ReactJS: React Performance – Sử dụng useMemo để tối ưu cho những tính toán phức tạp

React hooks rất là tuyệt vời khi nó cho phép chúng ta chỉ sử dụng duy nhất functional component trong app của chúng ta. Và chúng ta có thể đặt logic và state bên trong function quá là tiện lợi. Hơn thế nữa nó cho phép chúng ta tạo custom hook và sử dụng lại khi cần thiết. Điều này khó làm được với class component. Very nice!!

Có một lưu ý là những function trong component sẽ được chạy lại sau mỗi lần render.

function Distance({x, y}) {
  const distance = calculateDistance(x, y)
  return (
    <div>
      The distance between {x} and {y} is {distance}.
    </div>
  )
}

Ví dụ hàm calculateDistance luôn luôn được chạy lại khi component <Distance /> render lại vì một lý do gì đó. Cho dù kết quả của distance có bằng nhau nhưng nó vẫn bị chạy lại mỗi lần re-render. Ví dụ trong trường hợp component cha render lại thì component <Distance /> sẽ re-render.

Đó là lý do chúng ta sử dụng useMemo:

function Distance({x, y}) {
  const distance = React.useMemo(() => calculateDistance(x, y), [x, y])
  return (
    <div>
      The distance between {x} and {y} is {distance}.
    </div>
  )
}

React.useMemo nhận vào hai tham số đó là một function với return value và một array chứa những tham số thay đổi của function đó. Với useMemo mỗi lần render lại hàm calculateDistance chỉ được thực thi khi mà một trong x,y thay đổi, nếu không nó sẽ lấy kết quả trước đó vì với cùng một input (x,y) thì sẽ cho kết quả giống nhau (calculateDistance(x, y)) cho nên chúng ta sẽ chỉ lấy giá trị cũ. Điều này giúp tối ưu thời gian chạy của component, giả sử hàm calculateDistance của bạn chạy 2-3s thì hiệu suất sẽ tăng đáng kể nếu sử dụng useMemo trong trường hợp này.

Tối ưu hàm getItems

Giả sử chúng ta có một danh sách rất nhiều các thành phố trong demo sau đây. Chúng ta có Menu component nhận vào allItems và sau mỗi lần render hàm getItems được chạy lại. Hàm này chạy rất chậm vì nhận vào hàng ngàn item và sort chúng mỗi lần render. Điều này có thể làm App component render rất chậm. Nhiệm vụ của bạn là sử dụng React.useMemo để hạn chế chạy lại làm getItems nếu giá trị inputValue nó không thay đổi.

Hàm getItems

function getItems(filter) {
  if (!filter) {
    return allItems
  }
  return matchSorter(allItems, filter, { // filter và sort hàng ngàn items here
    keys: ['name'],
  })
}
function App() {
  const forceRerender = useForceRerender()
  const [inputValue, setInputValue] = React.useState('')

  // 🐨 bọc getItems bên trong `React.useMemo`
  const allItems = getItems(inputValue) // hàm này sort hàng ngàn items bên trong
  const items = allItems.slice(0, 100)

  const {
    selectedItem,
    highlightedIndex,
    getComboboxProps,
    getInputProps,
    getItemProps,
    getLabelProps,
    getMenuProps,
    selectItem,
  } = useCombobox({
    items,
    inputValue,
    onInputValueChange: ({inputValue: newValue}) => setInputValue(newValue),
    onSelectedItemChange: ({selectedItem}) =>
      alert(
        selectedItem
          ? `You selected ${selectedItem.name}`
          : 'Selection Cleared',
      ),
    itemToString: item => (item ? item.name : ''),
  })

  return (
    <div className="city-app">
      <button onClick={forceRerender}>force rerender</button>
      <div>
        <label {...getLabelProps()}>Find a city</label>
        <div {...getComboboxProps()}>
          <input {...getInputProps({type: 'text'})} />
          <button onClick={() => selectItem(null)} aria-label="toggle menu">
            ✕
          </button>
        </div>
        <Menu
          items={items}
          getMenuProps={getMenuProps}
          getItemProps={getItemProps}
          highlightedIndex={highlightedIndex}
          selectedItem={selectedItem}
        />
      </div>
    </div>
  )
}

export default App

Đơn giản bạn sử dụng React.useMemo như sau:

const allItems = React.useMemo(() => getItems(inputValue), [inputValue])

thaunguyen.com via Epic React by Kent C.Dodds

Leave a Comment