🌞

3 bước tối ưu hiệu năng React App bằng các API mới của React

Sửa bài viết này

Khi sử dụng function component, React cung cấp 3 phương thức để tối ưu: React.memo, useMemo, và useCallback, chúng ta cùng điểm qua 3 thằng này

Xét ví dụ

const ListPage = ({ data, title }) => (
    <>
        <Header title={title} />
        <List listItems={data} />
    </>
)

Component như trên (<ListPage />), khi nhận một data mới, tất cả component con bên trong là HeaderList sẽ re-render, mặc dù cái title không hề thay đổi. Nếu Header không tốn quá nhiều thời gian để render thì ko có vấn đề. Ngược lại dĩ nhiên là nếu render Header tốn rất nhiều thời gian, chúng ta phải xây lại để tối ưu hơn.

React.memo

const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
});

React.memo là một HOC, đọc lại bài này, nó sẽ nhớ kết quả render của component. Nếu component trả về một output giống hệt cho cùng một prop, đưa nó vào React.memo sẽ tiết kiệm tí thời gian.

const Header = ({ title }) => <h1>{title}</h1>

export default Header;

Wrap lại trong React.memo

const Header = ({ title }) => <h1>{title}</h1>

export default React.memo(Header);

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Cũng tương tự nó sẽ nhớ kết quả trả về, tuy nhiên nó sẽ có thêm phần gọi là array dependencies, là một danh sách các thằng mà nó phụ thuộc, nếu giá trị phụ thuộc thay đổi nó mới rọi render lại, không thể trả thẳng kết quả lần trước

const widgetList = useMemo(
    () => 
        widgets.map(w => ({
        ...w,
        totalPrice: someComplexFunction(w.price),
        estimatedDeliveryDate: someOtherComplexFunction(w.warehouse)
    })),
    [widgets]
);

Trong ví dụ trên, 1 component nhận một danh sách các widget, các widget này trước khi truyền vào sẽ được thêm vào 2 giá trị là total pricedelivery date. Nếu giá trị các widget không thay đổi khi render lại component, thì không cần thiết phải chạy qua các hàm someComplexFunction, someOtherComplexFunction. Sử dụng useMemo để ghi nhớ kết quả và bỏ qua trong trường hợp đó.

useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

Mục đích để chặn các lần render không cần thiết giữa component cha và con

const Parent = () => {
    const [showExtraDetails, setShowExtraDetails] = useState(false);
    return (
        <>
        <Child onClick={() => { showData(showExtraDetails); }/>
        </>
    )
}

1 component như vậy sẽ re-render cả cha và con cùng lúc, thậm chí component con có là PureComponent được wrap bên trong React.memo đi nữa, bởi vì onClick sẽ khác nhau trên mỗi lần render. Sử dụng useCallback chúng ta viết lại như sau

const Parent = () => {
    const [showExtraDetails, setShowExtraDetails] = useState(false);
    const handleClick = useCallback(
      () => {
        showData(showExtraDetails);
      },
      [showExtraDetails],
    );
    return (
        <>
        <Child onClick={handleClick} />
        </>
    )
}

Như vậy hàm handleClick sẽ giống nhau cho các lần render khác nhau, nó chỉ khác khi showExtraDetails thay đổi.

React: Optimize Components with React.memo, useMemo, and useCallback

Initializing...