Hầu như với những người mới làm quen với React ai cũng từng gặp qua chuyện console
hiện ra warning
như thế này
Đọc sơ qua mình cũng hiểu được là đang gặp một rắc rối nhỏ với React setState
api. State của một component vừa được gọi update trong khi nó đã unmount
rồi. Thông thường warning
này sẽ diễn ra trong 2 hoàn cảnh mà bản thân mình thấy hay gặp :
.then
, .catch
hoặc .finally
, nhưng component
chứa function này lại bị unmount trước khi promise chạy xong và thực thi code. setState
. Để mình làm một ví dụ nhỏ để mô phỏng lại trường hợp này
Đầu tiên mình tạo một function trả về một promise
mẫu
Mình tạo một component Parent
chứa component Child
Bên trong Child mình sẽ call fetchSomething
trong useEffect
lúc này đồng nghĩa với componentDidMount
. Trong Parent các bạn để ý sẽ có một button để toggle ẩn Child
đi, hiện giờ fetchSomething
sau khi chờ 5 giây sẽ gọi setFetchStatus
, nhưng trong thời gian chờ đó mình click toggle button, lúc này component Child unmount và khi xong 5 giây warning sẽ xuất hiện.
Vậy lỗi này có nguy hiểm không, thực sự thì tuỳ, nếu các bạn để nó xảy ra trên rất rất nhiều component mà thì việc tràn bộ nhớ mức độ nghiêm trọng sẽ tăng theo.
Ở đây mình sẽ có vài cách mình hay dùng để giải quyết việc này
Ở đây mình sẽ tạo một flag
để nhận biết là component đã unmount
hay chưa, nếu rồi thì mình không setState nữa, mình sẽ mô phỏng lại tiếp theo ví dụ phía trên
Nếu mà không gọi async function fetchSomething
trong useEffect
mà chỉ gọi khi click một button nào đó thì sao ?
Mình có thể chuyển flag isUnmounted
kia thành useRef
AbortController là một object controller global được support hầu hết trên các browser ( trừ IE :lol: ) dùng để cancel các Web request. Thường thì các bạn dùng axios
hoặc fetch
để tạo http request lên server. Mình sẽ ví dụ cách cancel
khi dùng fetch
Ở đây khi gọi fetch mình sẽ gắn signal và options init của request này tương ứng với abortController
vừa khởi tạo, khi unmount thì mình dùng hàm abort()
của controller để cancel.
Ở đây nếu các bạn đưa state
cần update ra global store của Redux
, lúc này đang wrap toàn bộ Web app thì cũng sẽ tránh được tình trạng này. Việc dùng Redux store cũng sẽ tránh bị memory leak khi chuyển route. Việc này các bạn có thể cân nhắc sử dụng.
!!! Một note lưu ý là khi dùng React useReducer hook
cũng sẽ giống như useState nên các bạn cũng cần phải handle cancel các asynchronous
calls nếu xảy ra warning
như trên.
Cảm ơn các bạn đã đọc bài ! <3