Viết RTK Query Service
Cấu trúc
API services nằm trong src/services/*.service.ts, dùng baseApi.injectEndpoints.
Ví dụ đầy đủ
// src/services/product.service.ts
import { baseApi } from "@/config/baseApi";
import type { CommonResponse, PaginationResponse } from "@vppos/core/types";
import type { Product, CreateProductPayload } from "@/types/product.type";
export const productApi = baseApi.injectEndpoints({
endpoints: (builder) => ({
// GET — Query
getProducts: builder.query<
PaginationResponse<Product>,
{ page: number; limit?: number; search?: string }
>({
query: ({ page, limit = 10, search }) => ({
url: "/products",
params: { page, limit, search },
}),
}),
// GET by ID — Query
getProductById: builder.query<CommonResponse<Product>, string>({
query: (id) => `/products/${id}`,
}),
// POST — Mutation
createProduct: builder.mutation<CommonResponse<Product>, CreateProductPayload>({
query: (body) => ({
url: "/products",
method: "POST",
body,
}),
}),
// PUT — Mutation
updateProduct: builder.mutation<
CommonResponse<Product>,
{ id: string; body: Partial<CreateProductPayload> }
>({
query: ({ id, body }) => ({
url: `/products/${id}`,
method: "PUT",
body,
}),
}),
// DELETE — Mutation
deleteProduct: builder.mutation<CommonResponse<null>, string>({
query: (id) => ({
url: `/products/${id}`,
method: "DELETE",
}),
}),
}),
});
// Export auto-generated hooks
export const {
useGetProductsQuery,
useLazyGetProductsQuery,
useGetProductByIdQuery,
useCreateProductMutation,
useUpdateProductMutation,
useDeleteProductMutation,
} = productApi;
Sử dụng trong component
Query (GET)
function ProductList() {
const { storeId } = useStoreSelection();
const [search, setSearch] = useState("");
const debouncedSearch = useDebounce(search, 300);
const { data, isLoading, isFetching } = useGetProductsQuery({
page: 1,
search: debouncedSearch,
});
if (isLoading) return <TableSkeleton />;
// render data.data...
}
Lazy Query (trigger thủ công)
const [trigger, { data, isFetching }] = useLazyGetProductsQuery();
const handleSearch = () => {
trigger({ page: 1, search: "keyword" });
};
Mutation (POST/PUT/DELETE)
const [createProduct, { isLoading }] = useCreateProductMutation();
const handleSubmit = async (data: CreateProductPayload) => {
try {
await createProduct(data).unwrap();
toastUtils.success("Tạo sản phẩm thành công");
} catch (err) {
toastUtils.error(getApiErrorMessage(err));
}
};
Quy tắc
mẹo
- Luôn dùng
CommonResponse<T>hoặcPaginationResponse<T>cho response type - Export tất cả hooks cần dùng
- Không tạo
useStateloading riêng khi đã có RTK Query - Không gọi
fetch/axiostrực tiếp trong component