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
(default0
ms): 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áistale
trên dev tool nó hiển thị là data của bạnstale
vàactive
cacheTime
(default5*60*1000
ms 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 < cacheTime
inactive
: 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
isLoading
orstatus === 'loading'
- Query chưa có dataisError
orstatus === 'error'
- Query xảy ra lỗiisSuccess
orstatus === 'success'
- Query thành công và data đã có sẵn
Những state về data
error
- NếuisError === true
thìerror
sẽ xuất hiện ở đâydata
- NếuisSuccess === true
thìdata
sẽ xuất hiện ở đây
Đặc biệt là fetchStatus
isFetching
orfetchStatus === 'fetching'
- Đang fetching API.isPaused
orfetchStatus === '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ớ
status
cho thông tindata
có hay khôngfetchStatus
cho thông tin vềqueryFn
có đ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
staleTime
giữ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 gianstaleTime
củ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 })
}
A
component đượ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ì sau0
s
- Vì không có query nào với
- Bây giờ thì
B
component đượ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à đãstale
nên nó sẽ fetch api tại componentB
- Không quan trọng function
fetchTodos
ởA
vàB
có giống nhau hay không, việc fetch api tạiB
sẽ cập nhật tất cả các state query liên quan củaB
vàA
vì 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 comonentA
vàB
cũng được cập nhật data mới
- Vì cache data
- Bây giờ thì
A
vàB
unmount, 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ì
inactive
nêncacheTime
sẽ bắt đầu đếm ngược 5 phút
- Vì
- Trước khi
cacheTime
hết thì ôngC
comopnent được mount. cache data['todos']
được trả về ngay lập tức choC
vàfetchTodos
sẽ 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ì
C
unmount - 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