Hook tối ưu hiệu suất useCallback trong React
Trong bài học này, chúng ta sẽ xem xét hook
tối ưu hiệu suất tiếp theo
useCallback.
Hook useCallback tương tự như API useMemo,
điểm khác biệt là hook đầu tiên
lưu vào bộ nhớ đệm giá trị giữa các lần render lại
màn hình, còn hook thứ hai - callback.
Điều này cho phép chúng ta không khởi chạy lại các
hàm tốn nhiều tài nguyên
khi không cần thiết và có thể
sử dụng khi
truyền hàm
vào các component con.
Hãy cùng tìm hiểu chi tiết hơn bằng ví dụ.
Đầu tiên, hãy tạo component App
và tạo state num trong đó:
const [num, setNum] = useState(0);
Giả sử chúng ta có một nút bấm, khi click
vào đó num sẽ tăng lên
1, và một đoạn văn, trong đó chúng ta
sẽ hiển thị giá trị num:
return (
<div>
<button onClick={() => setNum(num + 1)}>click</button>
<p>clicks: {num}</p>
</div>
);
Bây giờ, giả sử trong
App còn hiển thị một danh sách nào đó
với các phần tử, mà chúng ta sẽ bổ sung
bằng cách nhấn vào một nút khác. Để lưu trữ
các phần tử của danh sách này, chúng ta sẽ tạo
state items:
const [items, setItems] = useState([]);
Và sau đó viết hàm addItem
để thêm chúng:
function addItem() {
setItems([...items, 'new item']);
}
Bây giờ hãy viết code để hiển thị
các phần tử của danh sách và tách nó ra thành component con
Items, component này sẽ nhận mảng các phần tử
và hàm để thêm chúng dưới dạng props. Đừng quên
thêm việc ghi ra console để thấy
khi nào Items của chúng ta
render lại:
function Items({ items, addItem }) {
const result = items.map((item, index) => {
return <p key={index}>{item}</p>;
});
console.log('Items render');
return (
<div>
<h3>Our items</h3>
{result}
<button onClick={addItem}>add item</button>
</div>
);
}
export default Items;
Hãy đặt Items ở cuối component
App và truyền cho nó mảng
items và hàm để thêm
phần tử addItem:
return (
<>
<div>
<button onClick={() => setNum(num + 1)}>click</button>
<p>clicks: {num}</p>
<br />
</div>
<Items items={items} addItem={addItem} />
</>
);
Và bây giờ hãy nhấn vào các nút
và đảm bảo rằng num tăng lên và
phần tử mới được thêm vào danh sách.
Và khi mở console, chúng ta sẽ thấy rằng
danh sách của chúng ta render lại mỗi
lần, ngay cả khi chúng ta click vào nút
mà nút đó làm tăng num.
Nếu chúng ta có một danh sách nhỏ, thì mọi thứ
đều ổn, nhưng nếu giả định rằng nó
sẽ có kích thước lớn và có nhiều thứ khác ở đó thì sao?
Không sao - bạn sẽ nói, bởi vì trong bài học
trước chúng ta đã xem xét API memo,
để tránh các lần render lại không cần thiết
của component.
Vậy hãy bọc component
Items của chúng ta vào memo và thế là xong.
Nhân tiện, điều này có thể được thực hiện ngay
khi export Items:
export default memo(Items);
Đừng quên import memo:
import { memo } from 'react';
Và bây giờ hãy mở console và nhấn
vào các nút. Mọi nỗ lực đều vô ích! Chúng ta
đã ghi nhớ hóa component, nhưng khi nhấn
vào nút 'click' component
Items vẫn
render lại mỗi lần.
Vấn đề là khi component cha
render lại, các hàm của nó
được tạo lại từ đầu - điều này áp dụng cho cả hàm
addItem của chúng ta, hàm mà chúng ta truyền vào
Items.
Chính tại thời điểm này, hook
useCallback sẽ giúp chúng ta. Hãy áp dụng
nó. Đầu tiên, import nó vào
App:
import { useCallback } from 'react';
Sau đó, chuyển đổi khai báo hàm đơn giản
addItem thành
Function Expression, chỉ định
tham số đầu tiên cho useCallback
là hàm của chúng ta dưới dạng callback. Tham số
thứ hai trong dấu ngoặc vuông, chúng ta chỉ định
các dependencies - tất cả các biến phản ứng,
tham gia vào hàm, trong trường hợp của chúng ta
đó là mảng items:
const addItem = useCallback(() => {
setItems(() => [...items, 'New item']);
}, [items]);
Hoàn tất! Bằng cách này, chúng ta đã lưu vào bộ nhớ đệm
hàm. Hãy nhấn lại vào các nút và
thấy rằng bây giờ khi nhấn vào nút
'click' component con của chúng ta không
render lại nữa.
Tạo component App, đặt
vào đó một đoạn văn có văn bản. Tạo
state với giá trị ban đầu 'text'
và hiển thị nó trong đoạn văn. Hãy để khi click
vào đoạn văn, vào cuối văn bản của nó
thêm một dấu chấm than.
Tạo component con Products,
trong đó bạn sẽ có một nút để thêm
sản phẩm mới. Đặt nó vào App.
Trong component cha, tạo state
với mảng sản phẩm và hàm thêm
sản phẩm mới. Truyền chúng vào
component con dưới dạng props, hiển thị trong đó
mảng đã truyền dưới dạng danh sách ul.
Trong Products, ghi ra console văn bản
'products render'.
Bọc Products vào memo.
Click vào đoạn văn và nút. Đảm bảo rằng,
khi click vào đoạn văn, component con
vẫn render lại.
Lưu vào bộ nhớ đệm hàm để thêm
sản phẩm, bằng cách bọc nó trong hook useCallback.
Click vào đoạn văn và nút. Đảm bảo rằng,
khi click vào đoạn văn, component con
không còn render lại nữa.