Chúng ta có thể sử dụng state trước đó để tạo ra state mới bằng cách truyền một callback vào set function của useState. Ta gọi callback này là updater function và cách làm này được gọi là functional update.
import { useState } from "react"
function App() {
const [number, setNumber] = useState(0)
function handleClick() {
setNumber((n) => n + 1)
setNumber((n) => n + 1)
setNumber((n) => n + 1)
}
return (
<div>
<h1>{number}</h1>
<button onClick={addOne}>Add Three</button>
</div>
)
}React Batches State Updates
React sẽ chờ các đoạn code ở trong các event handler chạy xong rồi mới thực hiện xử lý state. Các updater function và các hành động của set function sẽ được lưu ở trong một hàng đợi và sẽ được xử lý bởi useState ở lần render tiếp theo.
Điều này giống như khi order đồ ăn ở nhà hàng: chúng ta có thể thay đổi món chúng ta muốn gọi tùy thích trước khi đưa ra quyết định cuối cùng.
Minh họa:

Đây được gọi là cơ chế batching ở trong React. Cơ chế này giúp giảm số lần re-render không cần thiết ở trong ứng dụng.
Trong đoạn code ở trên, 3 updater function sẽ được đưa vào hàng đợi trước khi useState thực hiện xử lý chúng ở lần render tiếp theo.
Hàng đợi sẽ có dạng như sau:
| queued update | n | returns |
|---|---|---|
n => n + 1 | 0 | 0 + 1 = 1 |
n => n + 1 | 1 | 1 + 1 = 2 |
n => n + 1 | 2 | 2 + 1 = 3 |
Sau khi xử lý xong 3 updater function thì useState sẽ lưu giá trị cuối cùng của state là 3 rồi trả về cho biến number.
Các updater function sẽ được chạy trong quá trình rendering. Do đó, nó cần phải là pure function và chỉ có thể trả về kết quả1.
What Happens if You Update State After Replacing It?
Xét đoạn code dưới đây:
<button onClick={() => {
setNumber(number + 5)
setNumber(n => n + 1)
}}>Quá trình xử lý:
setNumber(number + 5):number = 0nên lời gọi set function này tương đương vớisetNumber(5). React thêm vào hành động “Thay thế state thành5” vào hàng đợi.setNumber(n => n + 1):n => n + 1là một updater function. React sẽ thêm nó vào hàng đợi.
Hàng đợi sẽ có dạng như sau:
| queued update | n | returns |
|---|---|---|
Thay thế thành 5 | 0 (không sử dụng) | 5 |
n => n + 1 | 5 | 5 + 1 = 6 |
Có thể thấy, việc dùng setState(5) tương tự với setState(n => 5) nhưng giá trị n lại không được sử dụng.
What Happens if You Replace State After Updating It?
Xét đoạn code sau:
<button onClick={() => {
setNumber(number + 5)
setNumber(n => n + 1)
setNumber(42)
}}>Quá trình xử lý:
setNumber(number + 5):number = 0nên lời gọi set function này tương đương vớisetNumber(5). React thêm vào hành động “Thay thế state thành5” vào hàng đợi.setNumber(n => n + 1):n => n + 1là một updater function. React sẽ thêm nó vào hàng đợi.setNumber(42): React sẽ thêm hành động “Thay thế state thành42” vào hàng đợi.
Hàng đợi sẽ có dạng như sau:
| queued update | n | returns |
|---|---|---|
Thay thế state thành 5 | 0 (không sử dụng) | 5 |
n => n + 1 | 5 | 5 + 1 = 6 |
Thay thế state thành 42 | 6 (không sử dụng) | 42 |
Có thể thấy, đối số của set function nếu là updater function thì sẽ được đưa vào hàng đợi còn các giá trị thông thường thì sẽ ghi đè lên state.
Resources
Footnotes
-
xem thêm Keeping Components Pure ↩