Using Function as as Dependency
Xét component sau:
import { useEffect } from "react"
function Logger() {
function logData() {
console.log("data")
}
useEffect(() => {
logData()
}, [])
return null
}Trong component trên, hàm logData không sử dụng các reactive value nên ta dùng dependency array rỗng để đảm bảo setup function của useEffect chỉ được chạy một lần.
Tuy nhiên, nếu hàm logData sử dụng reactive value thì ta bắt buộc phải đặt hàm đó vào dependency array:
// Wrong way ❌
import { useEffect } from "react"
function Logger({ data }) {
function logData() {
console.log(data)
}
useEffect(() => {
logData()
}, [logData])
return null
}Lúc này, đoạn code của ta gặp một vấn đề như sau: mỗi lần data thay đổi thì component sẽ được re-render.
- Mà mỗi lần như vậy function
logDatasẽ được tạo ra ở một vùng nhớ khác với function cũ. - Ta đã biết hai reference object giống nhau nhưng khác vùng nhớ thì sẽ không bao giờ bằng nhau1.
- Dẫn đến, setup function sẽ được tái thực thi một cách không mong muốn do dependency của nó là hàm
logDatađã bị thay đổi.
Điều tương tự cũng xảy ra nếu logData có sử dụng state của component.
Để giải quyết vấn đề trên, ta có thể di chuyển hàm logData vào bên trong setup function và sử dụng dependency là data như sau:
// Correct way ✅
import { useEffect } from "react"
function Logger({ data }) {
useEffect(() => {
function logData() {
console.log(data)
}
logData()
}, [data])
return null
}Chúng ta cũng có thể giải quyết vấn đề trên bằng cách dùng hook useCallback để ghi nhớ hàm logData.
Using an Array or Object as a Dependency
Array và Object đều thuộc kiểu reference2. Mỗi khi component được re-render, tất cả các array và object đều sẽ được khởi tạo trên một vùng nhớ mới có tham chiếu khác so với lần render trước đó.
Vì vậy, nếu sử dụng array hoặc object như là các dependency của useEffect thì chúng ta sẽ gặp vấn đề về vòng lặp vô hạn.
Ví dụ sử dụng array làm dependency:
function App() {
const [count, setCount] = useState(0)
const fruits = ["🍎", "🍌", "🍊"]
useEffect(() => {
setCount(count + 1)
}, [fruits])
}Để giải quyết vấn đề trên, ta cần đảm bảo rằng tham chiếu của array hoặc object là không đổi giữa các lần render bằng cách đưa mảng vào trong setup function hoặc dùng hook useRef.
Ví dụ sử dụng useRef cho array:
function {
const [count, setCount] = useState(0)
const fruits = useRef(['🍎', '🍌', '🍊'])
useEffect(() => {
setCount(count + 1)
}, [fruits])
}Giải quyết tương tự với object.
Resources
Footnotes
-
Xem thêm JS Data Types. ↩
-
Xem thêm Non-primitive Data Type ↩