Series này sẽ khoản 10 video, xem hết series này bạn sẽ nắm vững được React Query và có thể tự tin xử lý mọi case thực tế
- Video 1: React query là gì? setup dev tool, gọi query
TanStack Query (tên mới) hay React Query là thư viện giúp quản lý các state bất đồng bộ như data từ api.
Sức mạnh của Tanstack Query
- Quản lý cache data và cập nhật cực kỳ đơn giản với zero config
- Không dùng global state, reducer để quản lý, không học thuật khó hiểu. Quên Redux được rồi đó!
- Có khả năng tương thích và mở rộng với mọi use-case
Từ khi biết đến Tanstack Query, mình đã tiết kiệm được thời gian code và sản phẩm cũng đem lại trải nghiệm người dùng tốt hơn.
Trả lời câu hỏi phổ biến:
Tanstack Query dùng gì để gọi API?
Tanstack Query không đảm nhận việc gọi API, việc gọi API sẽ thực hiện thông qua các thư viện bạn dùng như axios, fetch API. Còn Tanstack Query chỉ đảm nhận việc quản lý data và trigger khi cần thiết.
React Query có cơ chế caching hơi khác một chút so với RTK Query, nên anh em đừng lấy logic của RTK Query rồi suy ngược lại React Query cũng giống vậy nhé.
Anh em hãy dành ra 1 phút để quên đi cách caching của RTK Query 😁
staleTime(default0ms): Thời gian data được cho là đã cũ. Khi get data xong thì sau một thời gian bạn quy định thì data nó sẽ tự cũ. Lưu ý cáistaletrên dev tool nó hiển thị là data của bạnstalevàactivecacheTime(default5*60*1000ms tức 5 phút): Thời gian data sẽ bị xóa ra khỏi bộ nhớ đệm. Có thể data đã "cũ" nhưng nó chưa bị xóa ra khỏi bộ nhớ đệm vì bạn setstaleTime < cacheTime. Thường thì người ta sẽ setstaleTime < cacheTimeinactive: là khi data đó không còn component nào subcribe cả
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })result là một object chứa một vài state rất quan trọng: status, fetchStatus,...
Những state về các khoảnh khắc của data
isLoadingorstatus === 'loading'- Query chưa có dataisErrororstatus === 'error'- Query xảy ra lỗiisSuccessorstatus === 'success'- Query thành công và data đã có sẵn
Những state về data
error- NếuisError === truethìerrorsẽ xuất hiện ở đâydata- NếuisSuccess === truethìdatasẽ xuất hiện ở đây
Đặc biệt là fetchStatus
isFetchingorfetchStatus === 'fetching'- Đang fetching API.isPausedorfetchStatus === 'paused'- Query muốn fetch API nhưng bị tạm dừng vì một lý do nào đó.fetchStatus === 'idle'- Query không làm gì cả
Chỉ cần nhớ
statuscho thông tindatacó hay khôngfetchStatuscho thông tin vềqueryFncó đang chạy hay không
Một data mà đã stale thì khi gọi lại query của data đó, nó sẽ fetch lại api. Nếu không stale thì không fetch lại api (đối với trường hợp staleTime giữa các lần giống nhau)
Còn đối với trường hợp
staleTimegiữa 2 lần khác nhau thì nếu data của lần query thứ 1 xuất hiện lâu hơn thời gianstaleTimecủa lần query thứ 2 thì nó sẽ bị gọi lại ở lần thứ 2, dù cho có stale hay chưa. Ví dụ:useQuery({ queryKey: ['todos'], queryFn: fetchTodos, staleTime: 10*1000 })xuất hiện 5s trước, bây giờ chúng ta gọi lạiuseQuery({ queryKey: ['todos'], queryFn: fetchTodos, staleTime: 2*1000 })thì rõ ràng cái data của lần 1 dù nó chưa được cho là stale nhưng nó xuất hiện 5s trước và lâu hơn thời gian staleTime là 2s nên nó sẽ bị gọi lại ở lần 2.
Một data mà bị xóa khỏi bộ nhớ (tức là quá thời gian cacheTime) thì khi gọi lại query của data đó, nó sẽ fetch lại api. Nếu còn chưa bị xóa khỏi bộ nhớ nhưng đã stale thì nó sẽ trả về data cached và fetch api ngầm, sau khi fetch xong nó sẽ update lại data cached và trả về data mới cho bạn.
Caching là một vòng đời của:
- Query Instance có hoặc không cache data
- Fetch ngầm (background fetching)
- Các inactive query
- Xóa cache khỏi bộ nhớ (Garbage Collection)
Một ví dụ như thế này cho anh em dễ hiều:
Giả sử chúng ta dùng cacheTime mặc định là 5 phút và staleTime là 0.
function A() {
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}
function B() {
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}
function C() {
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}Acomponent được mount- Vì không có query nào với
['todos']trước đó, nó sẽ fetch data - Khi fetch xong, data sẽ được cache dưới key là
['todos'] - hook đánh dấu data là
stale(cũ) vì sau0s
- Vì không có query nào với
- Bây giờ thì
Bcomponent được mount ở một nơi nào đó- Vì cache data
['todos']đã có trước đó, data từ cache sẽ trả về ngay lập tức cho componentB - Vì cache data
['todos']được cho là đãstalenên nó sẽ fetch api tại componentB- Không quan trọng function
fetchTodosởAvàBcó giống nhau hay không, việc fetch api tạiBsẽ cập nhật tất cả các state query liên quan củaBvàAvì 2 component cùng key => cùng subcribe đến một data
- Không quan trọng function
- Khi fetch thành công, cache data
['todos']sẽ được cập nhật, cả 2 comonentAvàBcũng được cập nhật data mới
- Vì cache data
- Bây giờ thì
AvàBunmount, không còn sử dụng nữa, không còn subcribe đến cache data['todos']nữa nên data['todos']bị cho làinactive- Vì
inactivenêncacheTimesẽ bắt đầu đếm ngược 5 phút
- Vì
- Trước khi
cacheTimehết thì ôngCcomopnent được mount. cache data['todos']được trả về ngay lập tức choCvàfetchTodossẽ chạy ngầm. Khi nó hoàn thành thì sẽ cập nhật lại cache với data mới. - Cuối cùng thì
Cunmount - Không còn ai subcribe đến cache data
['todos']trong 5 phút tiếp theo nữa và cache data['todos']bị xóa hoàn toàn