Cảm ơn bạn!
React memo là gì? Hạn chế re-render component với React memo
React.memo()
Trong một số trường hợp, component của chúng ta re-render, ngay cả khi component này có props
không thay đổi. Có rất nhiều nguyên nhân dẫn đến một component re-render. Một tình huống khá phổ biến đó là khi parent component
thay đổi state kéo theo các child component re-render.
Để cải thiện performance cho website sử dụng React, chúng ta có thể cải thiện bằng cách hạn chế các re-render không cần thiết. Để làm điều đó thì React giới thiệu một feature là React.memo()
.
React.memo()
sẽ giúp chúng ta hạn chế các re-render bằng cách kiểm tra xem props
của component có thay đổi hay không.
Khi một component được wrap
bởi React.memo()
, React sẽ ghi nhớ(memoizes) kết quả của lần render này, và trước lần render tiếp theo, nếu new props không thay đổi so với lần ghi nhớ trước, React sẽ reuse kết quả nó đã ghi nhớ và bỏ qua lần render này.
Để hiểu rõ hơn React.memo()
chúng ta cùng xem một ví dụ:
Ở ví dụ trên, khi click vào button update state
, state của parent thay đổi dẫn đến các child component re-render
. Như các bạn thấy, component <Post />
có props không thay đổi, nhưng khi parent update state thì <Post />
sẽ bị re-render và trong trường hợp này không có gì thay đổi trong component <Post />
, nên việc re-render component này là không cần thiết ^^.
function App() {
// Thay đổi state sẽ re-render child component
const [count, setcount] = useState(0);
return (
<>
<div>
<b>Update state App </b>
<button onClick={() => setcount(count + 1)}>
UPDATE STATE ({count})
</button>
</div>
<Post title="Tìm hiểu React.memo()" author="Nguyen Anh Vu" />
</>
);
}
function Post({ title, author }) {
console.log("Không sử dụng React.memo");
return (
<div>
<div>Bài viết: {title}</div>
<div>Tác giả: {author}</div>
</div>
);
}
Khi sử dụng React.memo()
ta sẽ hạn chế được re-render không cần thiết cho <Post />
.
Để sử dụng React.memo()
cho một component. Ta cần truyền một function component
vào React.memo()
.
const MemoizedComponent = React.memo(function MyComponent(props) {
// re-render nếu props thay đổi
});
Ở ví dụ trên thì ta sẽ wrap component <Post />
như sau:
const PostUseMemo = React.memo(function ({ title, author }) {
console.log("Sử dụng React.memo");
return (
<div>
<div>Bài viết: {title}</div>
<div>Tác giả: {author}</div>
</div>
);
});
Các bạn có thể xem ở phần Console
trong codesandbox, component sử dụng memo
sẽ không re-render lại vì props title
, author
không thay đổi sau mỗi lần update state của parent component.
Các bạn có thể compare props bằng cách truyền một function vào đối số thứ 2 của memo
.
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/* return true khi các giá trị trong prevProps và nextProps bằng nhau. */
}
export default React.memo(MyComponent, areEqual);
Để kiểm tra props có thay đổi hay không, React sử dụng shallow compare
để so sánh prevProps
và nextProps
. Mình đã có một bài viết về shallow compare
, các bạn có thể đọc tại đây: Shallow Compare trong React là gì?.
Để kiểm tra props ở ví dụ trên, ta có thể triển khai như sau:
function areEqual(prevProps, nextProps) {
return prevProps.title === nextProps.title
&& prevProps.author === nextProps.author;
// return true => không re-render
}
Nếu trong trường hợp
<Post />
có sử dụng cácuseState
,useReducer
hayuseContext
thì việc sử dụngReact.memo
sẽ không ngăn component này re-render. Đây là một lưu ý các bạn cần nắm ^^.