Thông thường trong ReactJs ta có thể sử dụng useEffect để fetch data từ api, nhưng tại sao bạn thấy cũng có một vài dự án người ta lại không sử dụng useEffect và thay vào đó là sử dụng react-query (hay TanStack Query) ? Bài viết này chúng tôi sẽ giúp bạn giải mã thắc mắc đó.
Danh mục bài viết
ToggleReact-query là gì?
Đơn giản thì react-query (hay TanStack Query) là thư viện hỗ trợ fetching, caching và updating dữ liệu bất đồng bộ của react.
Tại sao lại dùng react-query thay vì useEffect ?
Thông thường trong react để fetch dữ liệu từ server thì ta hay dùng useEffect.
const MyComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
const _fetch = async () => {
const res = await fetch("https://fstack.io.vn/api").then(response => response.json);
setData(response)
}
_fetch()
},[])
return (
// Some JSX here
)
}
Cách này hoạt động khá ổn, tuy nhiên rất rườm rà. Bạn sẽ phải viết 1 đống code chỉ để lấy dữ liệu từ server.
Sử dụng react-query (tanstack-query)
react-query cung cấp nhiều hooks cực kì đơn giản để fetch cũng như update data . Hỗ trợ caching, refetching giúp cải thiện trang Web của bạn.
Đầu tiên ta sẽ tìm hiểu cách để fetch dữ liệu sử dụng useQuery.
useQuery
Thông thường useQuery thường được dùng để lấy dữ liệu (Get).
Để sử dụng hook useQuery , ta phải truyền ít nhất 2 tham số:
- Tham số đầu tiên là queryKey
- Tham số thứ 2 là hàm trả về 1 promise: Resolve data, hoặc Throw error
- Tham số thứ 3 là các options (ta sẽ tìm hiểu ở bên dưới).
queryKey được sử dụng để refetching, caching và chia sẻ dữ liệu giữa các component với nhau.
Sau đây tôi sẽ có 1 ví dụ sử dụng useQuery cơ bản:
const Example=()=> {
const { isPending, error, data } = useQuery({
queryKey: ['todos'],
queryFn: () =>
fetch('https://fstack.io.vn/api').then((res) =>
res.json(),
),
})
if (isPending) return 'Loading...'
if (error) return 'An error has occurred: '
return (
// Some JSX here
)
}
export default Example
useQuery trả về những thông tin cần thiết như data , isLoading hay isError .(Bạn có thể xem thêm một số thông tin khác ở đây)
useMutation
useMutation khác với useQuery, được sử dụng để tạo,thay đổi hoặc xóa dữ liệu.
Để sử dụng hook useMutation, ta phải truyền ít nhất 1 tham số:
- Tham số thứ nhất là hàm trả về 1 promise: Resolve data hoặc Throw error.
- Tham số thứ 2 là các options.
function App() {
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
return (
{mutation.isLoading ? (
'Adding todo...'
) : (
<>
{mutation.isError ? (
An error occurred: {mutation.error.message}
) : null}
{mutation.isSuccess ? Todo added! : null}
>
)}
)
}
Cũng như useQuery, useMutation cũng trả về những thông tin cần thiết như isLoadding hay isError. (Bạn có thể xem thêm một số thông tin khác ở đây).
Tuy nhiên, useMutation lại trả về mutate thay vì data (như ví dụ trên). Khi gọi hàm mutate thì hàm số đầu tiên của useMutation sẽ được gọi.
Cơ chế caching
Trước tiền bạn phải nắm được một số lí thuyết quan trọng :
- StaleTime: (default 0 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ũ.(tự set thông qua :staleTime).
- CacheTime: (default là 5*60*1000 ms tức là 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 khỏi bộ nhớ đệm vì bạn set "staleTime < cacheTime". Thường thì người ta sẽ set "staleTime < cacheTime".
Tôi có một ví dụ đơn giản về chức năng phân trang:
const Home = () => {
const pagination = useQueryString();
const { data } = useQuery({
queryKey: ["products", pagination.page],
queryFn: () =>
getProductService(
+pagination.page ? +pagination.page : 1,
+pagination.pageSize ? +pagination.pageSize : 4
),
});
return (
{data?.items && data?.items && (
)}
{data?.meta.totalIteams && (
index + 1
)}
/>
)}
);
};
export default Home;

Khi bạn chuyển sang page 2 thì nó sẽ gọi api để lấy data ở page 2 và data đó nó sẽ trở thành data cũ (do tôi để mặc định staleTime là 0ms) và được lưu ở bộ nhớ đệm sau 5 phút mới bị xóa đi (mặc định là 5 phút nếu ta không set CacheTime).(và data page 1 cũng tương tự.)
Do đó khi ta trở lại page 1 thì data của page 1 vẫn còn được lưu trong bộ nhớ (nếu thời gian < 5 phút) thì thay vì đợi api trả dữ liệu mới về nó sẽ lấy dữ liệu page 1 đã gọi trước đó để render trước và vẫn gọi api ngầm để lấy dữ liệu mới , nếu dữ liệu mới có sự thay đổi so với dữ liệu cũ nó sẽ được cập nhật lại data để render từ đó giúp cải thiện UI và UX.

Tổng kết
Tổng kết lại thì react-query là một thư viện rất đáng để thử, còn rất nhiều tính năng hay của react-query mà mình chưa đề cập tới, bạn có thể xem docs của react-query (tanstack-query) ở đây:
Ở trên là 1 số chia sẻ về react-query của mình, vì đây đa phần là kiến thức mình tự học nên có thể bài viết này có thể có nhiều chỗ chưa chính xác và thiếu sót, mong mọi người góp ý ở dưới phần bình luận để bài viết thêm hoàn chỉnh và xây dựng một cộng đồng nơi mọi người có thể chia sẻ kinh nghiệm lập trình cho nhau 😘.