Nhảy tới nội dung

React query ( Tanstack Query ) rất tuyệt nhưng tôi đã ngừng sử dụng nó

· 6 phút để đọc
Phạm Quyết Thắng
ghi chú

This post is not complete!

React Query ( TanStack Query ) là gì ?

React Query là thư viện mã nguồn mở của TanStack, hiện tại nó được gọi với tên chính thứ là TanStack Query và không chỉ còn có thể sử dụng được trên react mà có thể sự dụng nó với hầu hết các framework frontend khác, Mình sẽ vẫn dùng tên React Query trong toàn bộ bài viết vì tính quen thuộc của nó.

React Query được thiết kế để làm cho việc làm việc với dữ liệu trở nên dễ dànghiệu quả hơn trong các ứng dụng React. React Query cung cấp các hooks như useQueryuseMutation để thực hiện các truy vấn dữ liệu và cập nhật dữ liệu một cách linh hoạt.

React Query tuyệt vời như thế nào ?

React-Query là một công cụ mạnh mẽ, nó giúp chúng ta giải quyết rất nhiều bàn toán về giao tiếp với REST API vốn rất phức tạp trước kia một cách đơn giản và ngắn gọn.

Một vài ưu điểm của React-Query có thể kể ra như:

  • Automatic Loading State Management: React-Query tự động quản ký các trạng thái truy vấn dữ liệu đang được thực hiện, Reacy Query sẽ tự động gắn cờ isLoading = true khi bắt đầu call api và gắn isLoading = false khi nó kết thúc. Ngoài ra còn nhiều trạng thái khác như là isError, isSuccess, isIdle, isFetching.
  • Caching and Deduplication: React Query có khả năng lưu trữ cache, loại bỏ dữ liệu trùng lặp và ngăn cản việc gọi các API trùng lặp diễn ra. Bạn có thể cài đặt thời gian bộ nhớ cache được lưu, và các trường hợp đặc biệt cần tải lại dữ liệu ( Ví dụ như mỗi lần vào lại tab hay mỗi lần scroll đến phần tử, ...).
  • Query Dependencies: React Query cung cấp một cách để tối ưu hóa quá trình tìm nạp dữ liệu bằng cách sử dụng khái niệm gọi là “phụ thuộc truy vấn”. Đây là các biến mà khi được thay đổi sẽ kích hoạt việc tìm nạp lại dữ liệu. Cách thức hoạt động của nó khá giống với Dependencies của các hook useEffect, useMemo hay useCallback

Ví dụ sử dụng React-Query:

Đây là 1 ví dụ sử dụng React-Query để Get data:

// Sử dụng React Query
export const TodoPage = () => {
const { isLoading, error, data } = useQuery(["getTodo"], () =>
fetch("https://dummy.codeduthu.com/todos").then((res) => res.json())
);

if (isLoading) return "Loading...";

if (error) return "An error has occurred: " + JSON.stringify(error);

return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.task}</li>
))}
</ul>
);
};

Nó đơn giản hơn rất nhiều nếu so sánh với cách fetch dữ liệu khi không có react-query:

// Không sử dụng React Query
export const TodoPage = () => {
const [data, setData] = useState([]);
const [error, setError] = useState();
const [isLoading, setIsLoading] = useState(false);

useEffect(() => {
setIsLoading(true);
fetch("https://dummy.codeduthu.com/todos")
.then((res) => res.json())
.then((data) => setData(data))
.catch((error) => setError(error))
.finally(() => {
setIsLoading(false);
});
}, []);

if (isLoading) return "Loading...";

if (error) return "An error has occurred: " + JSON.stringify(error);
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.task}</li>
))}
</ul>
);
};

Từ ví dụ nhỏ bên trên bạn đã thấy được về cú pháp nó đã ngắn gọn hơn nhiều so với cách sử dụng useEffect bình thường và bạn còn thấy nó tiện lợi hơn nữa khi sử lý các bài toán phức tạp hơn liện quan đến phân trang, tìm kiếm hay là infinity scroll.

Một tác động khác giữa 2 cách trên là khi dử dụng useEffect, do vòng đời của React việc gọi API get todos kia sẽ bị thực hiện 2 lần còn với react-query thì không. Bạn có thể tự kiểm nghiệm nó trong tab network của devtool react-query-network

Điều gì khiến mình ngừng sử dụng React Query ?

Okay, ở ví dụ trên mình đã so sánh việc dùng React Query và cách sử lý với useEffect + useState nhưng thực tế thế nào ?

Hầu hết hiện nay các ứng dụng React đều sử dụng Redux, việc thao tác với API cũng được kết hợp với Redux và những ví dụ kể trên của mình không còn mấy ý nghĩa nữa.

Việc xuất hiện redux-toolkit càng làm cho mọi thứ dễ dàng hơn khi api được handle trong createAsyncThunk, data được lưu trong store của redux các trạng thái cũng được handle cực kỳ tốt khi redux cho chúng ta bắt được các trạng thái pending, fulfilledrejected trong reducer.

Đến đây bạn vẫn thấy rằng là: ừ thì React Query vẫn ngắn gọn hơn nhiều và đáng để sử dụng đúng không? . Thì đúng vậy, còn rất nhiều vấn đề redux không thể giải quyết và chúng ta cần phải dùng React-Query, ví dụ như bạn vẫn cần phải dispatch một action call API trong useEffect và có thể vẫn bị dublicate query.

Mình cũng đã nghĩ như thế và bắt đầu thay thế hoàn toàn các đoạn code call API trong các projects bằng React Query. Nó quá tiện lợi, nhiều tính năng.

Nhưng đôi lúc nó cũng nảy sinh ra nhiều phiền toái. Lượng logic mình dùng với redux còn rất nhiều và nhiều lúc thật khó để kết hợp react-query với phần còn lại được sử dụng bằng redux. Mặc dù về lý thuyết mình vẫn có thể đưa data của react-query vào store của redux bằng cách dispatch một action setData trong callback onSuccess của react-query.

Xem ví dụ này:

const dispatch = useDispatch();

useQuery(["getData"], () => getDataApi(), {
onSuccess: (res) => dispatch(setData(res)),
});

Mình đã làm một video giới thiệu về RTK-Query, bạn có thể xem qua nó:

React-Query và Rtk-Query bạn nên chọn gì ?

Kết luận