Installation

Để sử dụng React Query, trước tiên ta cần cài đặt hai package sau đây:

yarn add @tanstack/react-query @tanstack/react-query-devtools

Package thứ hai là của React Query DevTools.

Setup

Import các thành phần cần thiết từ @tanstack/react-query:

import { QueryClient, QueryClientProvider } from "@tanstack/react-query"

Trước tiên, tạo ra một query client thông qua constructor của QueryClient như sau:

const queryClient = new QueryClient()

Bọc component QueryClientProvider ở bên ngoài App với client là queryClient vừa tạo ở trên như sau:

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </StrictMode>,
)

Tiếp theo, import ReactQueryDevtools và chèn ở sau component App như sau:

// Existing import ...
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
 
createRoot(document.getElementById("root")).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      <ReactQueryDevtools />
    </QueryClientProvider>
  </StrictMode>,
)

Query

Để tạo một query giúp thực hiện truy vấn dữ liệu, ta cần dùng hook useQuery từ @tanstack/react-query.

import { useQuery } from "@tanstack/react-query"

Hook này nhận vào một object, bao gồm hai thuộc tính quan trọng:

  • queryKey: là một mảng gồm nhiều giá trị dùng để định danh cho query. Hoạt động tương tự như tag của RTK Query (xem thêm Automated Re-fetching in RTK Query).
  • queryFn: là một callback thực hiện gửi request đến API và trả về một Promise có chứa dữ liệu.

Ví dụ:

const productsQuery = useQuery({
  queryKey: ["products"],
  queryFn: async () => {
    const res = await axios.get(`${API}/products`)
    return res.data
  },
})

Giá trị trả về của useQuery là một query, bao gồm các thuộc tính quan trọng sau:

  • data: kết quả trả về của query.
  • error: lỗi của query.
  • status: trạng thái của query, bao gồm các giá trị: loading, successerror.
  • isLoading, isSuccessisError: các trạng thái của query ở dạng boolean.
  • fetchStatus: trạng thái của fetching, bao gồm các giá trị : fetching, idlepaused1.

Gọi sử dụng query productsQuery ở trên như sau:

function App() {
  const productsQuery = useQuery({
    // ...
  })
 
  if (productsQuery.isLoading) return <h1>Loading...</h1>
  if (productsQuery.isError) {
    return <pre>{JSON.stringify(productsQuery.error)}</pre>
  }
 
  return (
    <div>
      {productsQuery.data.map((product) => (
        <div key={product.productId}>{product.name}</div>
      ))}
    </div>
  )
}

Mutation

Để tạo ra một mutation giúp thực hiện các mutation request (là các request thực hiện thay đổi dữ liệu), ta cần dùng hook useMutation từ @tanstack/react-query:

import { useMutation } from "@tanstack/react-query"

Hook này cũng nhận vào một object tương tự như useQuery. Thuộc tính mutationFn của object giúp chỉ định callback thực hiện gửi mutation request.

Ví dụ:

const updateProductPriceMutation = useMutation({
  mutationFn: async (newPrice) => {
    const product = productQuery.data
    const body = { ...product, price: newPrice }
    const res = await axios.put(`${API}/products/${productId}`, body)
    return res.data
  },
})

Giá trị trả về của useMutation là một mutation mà có các thuộc tính tương tự như một query chẳng hạn như data, error, isLoading, isError, …

Gọi sử dụng mutation ở trên như sau:

<button
  disabled={updateProductPriceMutation.isLoading}
  onClick={() => {
    updateProductPriceMutation.mutate(Math.floor(Math.random() * 100))
  }}
>
  Random a new price
</button>

Resources

Footnotes

  1. React Query coi loading và fetching là hai quá trình khác nhau, tương tự như RTK Query (xem thêm Queries in RTK Query).