- vừa được xem lúc

React.memo và Shallow Compare

0 0 6

Người đăng: Mokieee

Theo Viblo Asia

Giới thiệu

Chào tất cả các bạn. Hôm nay mình sẽ cùng tìm hiểu về một chủ đề khá thú vị về React, đó chính là memo, một khái niệm được React thêm vào từ version 16.6.

Trong React, việc re-render lại một component khi props và state thay đổi là cách để react update data mới cho component.

Tuy nhiên, khi xử lý với những component phức tạp, việc re-render nhiều lần sẽ trực tiếp ảnh hưởng tới hiệu suất của trang web.

Để tối ưu hiệu suất, cần phải tránh re-render những thứ không cần thiết. Các bạn cũng có thể tìm hiểu thêm về re-render trong link.

image.png

Dưới đây là một ví dụ

import { memo, useState } from 'react'; const Greeting = ({ name }) => { console.log("Greeting was rendered at", new Date().toLocaleTimeString()); return <h3>Hello{name && ', '}{name}!</h3>;
}; export default function MyApp() { const [name, setName] = useState(''); const [address, setAddress] = useState(''); return ( <> <label> Name{': '} <input value={name} onChange={e => setName(e.target.value)} /> </label> <label> Address{': '} <input value={address} onChange={e => setAddress(e.target.value)} /> </label> <Greeting name={name} /> </> );
}

Trong ví dụ này, bất cứ khi nào name hoặc address thay đổi thì toàn bộ MyApp sẽ re-render khiến Greeting là childComponent cũng re-render theo.

Mặc dù address không liên quan tới Greeting nhưng khi khí address thay đổi thì Greeting vẫn sẽ re-render theo.

Để tối ưu cho trường hợp này, ta phải hạn chế Greeting re-render nhiều lần và sẽ chỉ re-render khi props của nó là name thay đổi.

Lấy ý tưởng từ PureComponent và shouldComponentUpdate với mục đích skip render lại nếu props không thay đổi, memo ra đời như một sự kế thừa khi có thể linh hoạt sử dụng trong functionComponent thay vì classComponent.

React.memo

memo lets you skip re-rendering a component when its props are unchanged.

Bây giờ với memo ta có thể control việc re-render của Greeting bằng việc wrapper nó.

Trong ví dụ này, memo sẽ chỉ re-render nếu props của nó là name thay đổi.

import { memo, useState } from 'react'; const Greeting = memo({ name }) => { console.log("Greeting was rendered at", new Date().toLocaleTimeString()); return <h3>Hello{name && ', '}{name}!</h3>;
}); export default function MyApp() { const [name, setName] = useState(''); const [address, setAddress] = useState(''); return ( <> <label> Name{': '} <input value={name} onChange={e => setName(e.target.value)} /> </label> <label> Address{': '} <input value={address} onChange={e => setAddress(e.target.value)} /> </label> <Greeting name={name} /> </> );
}

Shallow Compare

Tương tự với PureComponent và shouldComponentUpdate, để nhận biết được sự thay đổi của props, memo cũng sử dụng so sánh Shallow Compare.

Shallow Compare hiểu đơn giản là so sánh nông sử dụng ===. Khi so sánh, ta cần đối chiếu giá trị và tham chiếu.

Với number, string, nó sẽ so sánh các giá trị của chúng. Tuy nhiên, khi so sánh các object, nó sẽ không so sánh các thuộc tính của chúng mà chỉ so sánh reference của chúng. Ví dụ

1 === 1 //true
{} === {} //false 
[] === [] //false 
{a:1} === {a:1} //false

Bản chất của let a = {}; và let b = {} là tham chiếu đến 2 địa chỉ khác nhau nên khi so sánh a === b ta sẽ nhận được kết quả là false.

Việc này dẫn đến một số lỗi ta hay gặp phải khi mới tiếp cận với react và memo. Dưới đây là một ví dụ

import { memo, useState } from 'react'; const Greeting = memo(({ name }) => { console.log(name); return <h3>Hello {name.firstName} {name.lastName}!</h3>;
}); export default function MyApp() { const [name, setName] = useState({firstName: '', lastName: ''}); return ( <> <label> First Name{': '} <input value={name.firstName} onChange={e => setName({...name, firstName: e.target.value})} /> </label> <label> Last Name{': '} <input value={name.lastName} onChange={e => setName({...name, lastName: e.target.value})} /> </label> <button onClick={() => setName({firstName: '', lastName: ''})} >Clear all</button > <Greeting name={name} /> </> );
}

Trong trường hợp này, khi click vào button Clear all nhiều lần, ta sẽ thấy Greeting luôn re-render mặc dù giá trị name luôn bằng {firstName: '', lastName: ''}.

image.png

Khi gọi setName({firstName: '', lastName: ''})} tức là đã tạo 1 tham chiếu mới và tham chiếu nó tới với name vì vậy khi React.memo so sánh sẽ trả về kết quả true và re-render lại Greeting

Để khắc phục việc này, ta thể làm như sau:

const initData = {firstName: '', lastName: ''}
const [name, setName] = useState(initData);
... <button onClick={() => setName(initData)} >Clear all</button > ....

Việc này giúp tham chiếu tới 1 giá trị initData nên React.memo so sánh sẽ trả về kết quả false và không re-render.

References

https://react.dev/reference/react/memo

https://truyenmai.com/react/react-re-render

Bình luận

Bài viết tương tự

- vừa được xem lúc

Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 30)

. Hello xin chào mọi người, mình đã trở lại và tiếp tục với phần 30 của series về Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết. Bắt đầu thôi nào.

0 0 45

- vừa được xem lúc

5 câu hỏi phỏng vấn Frontend giúp bạn tự tin hơn khi sử dụng bất đồng bộ trong Javascript

Một trong những điều khó khăn khi học Javascript là promises. Chúng không dễ hiểu và có thể cần một vài hướng dẫn và một thời gian kha khá để vận dụng chúng.

0 0 92

- vừa được xem lúc

Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 31)

Hello xin chào mọi người, mình đã trở lại và tiếp tục với phần 31 của series về Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết. Bắt đầu thôi nào.

0 0 44

- vừa được xem lúc

Những lý do khiến mình thích CSS custom properties hơn SASS variables?

Halo các bạn,. Lại là mình với một bài post liên quan tới chủ đề Front-end đây Mình còn nhớ hồi mình bắt đầu tìm hiểu và bị SASS lôi cuốn, mình đã nghĩ rằng mình sẽ chẳng bao giờ cần dùng đụng tới CSS

0 0 86

- vừa được xem lúc

Usability là gì? Những lưu ý khi thiết kế Usability

Usability là một yếu tố quan trọng trong sự thành bại của sản phẩm. Thật đáng tiếc khi sản phẩm làm ra ưu việt về tính năng, nhưng lại không được người dùng tiếp nhận, đơn giản chỉ vì khó sử dụng.

0 0 35

- vừa được xem lúc

7 Repos cho Front-End mà chính bạn còn không biết là bạn cần nó

. Những repos chẳng mấy khi được nhắc đến nhưng lại giúp bạn build mọi thứ nhanh hơn và tốt hơn nhiều. Chúng ta đang sống trong một thời đại có sẵn các công cụ và tài nguyên hoàn hảo, chúng chỉ cách t

0 0 37