Giới thiệu: React-Query là gì và tại sao nó quan trọng trong phát triển ứng dụng React

react-query, react-query là gì, lợi ích của react-query, react query hook

Lần trước mình có giới thiệu với mọi người về useSWR rồi, hôm nay mình cùng tìm hiểu một thư viện có chức năng tương tự, thậm trí còn mạnh mẽ hơn SWR đó là React-Query.

React-Query (hay Tanstack query) là một thư viện quản lý trạng thái dành cho React được tạo ra để quản lý và tương tác với các dữ liệu từ API hoặc bất kỳ nguồn dữ liệu nào. React-Query cung cấp một hệ thống mạnh mẽ để tải dữ liệu, lưu trữ cache, thực hiện các thao tác quản lý trạng thái như tạo, cập nhật và xóa dữ liệu một cách dễ dàng.

Có một số lợi ích quan trọng khi sử dụng React-Query trong phát triển ứng dụng React:


  • Dễ sử dụng: React-Query cung cấp API đơn giản và dễ hiểu, giúp giảm bớt thời gian và công sức khi phát triển ứng dụng.
  • Quản lý trạng thái tự động: React-Query tự động quản lý trạng thái dữ liệu và xử lý cập nhật tự động khi dữ liệu thay đổi. Điều này giúp giảm bớt mã lặp lại và tăng tính nhất quán trong ứng dụng.
  • Cache thông minh: React-Query lưu trữ cache dữ liệu để giảm số lượng yêu cầu mạng và tăng hiệu suất ứng dụng. Khi dữ liệu được yêu cầu lại, React-Query sẽ trả về dữ liệu từ cache mà không cần gửi yêu cầu mạng mới.
  • Tích hợp tốt với Suspense: React-Query tích hợp tốt với React Suspense, cho phép sử dụng khái niệm "suspense" để xử lý việc đợi cho dữ liệu được tải xuống từ server. Điều này giúp cải thiện trải nghiệm người dùng vì người dùng có thể hoạt động trên các thành phần khác trong khi dữ liệu đang được tải.
  • Hỗ trợ cho nhiều loại yêu cầu mạng: React-Query hỗ trợ cho nhiều loại yêu cầu mạng như GET, POST, PUT, DELETE, v.v. Nó cũng hỗ trợ các tính năng như xử lý phiên bản, xử lý lỗi, hủy yêu cầu, và nhiều hơn nữa.



Các bước cài đặt React-Query vào ứng dụng của bạn

cài đặt react-query, cấu hình react-query, import react-query, khởi tạo query client

Để cài đặt React-Query vào ứng dụng của bạn, bạn có thể thực hiện các bước sau:

1, Cài đặt React-Query bằng npm hoặc yarn:

  npm install react-query

Hoặc

  yarn add react-query


2, Tích hợp React-Query Provider cho ứng dụng của bạn bằng cách wrap (bao bọc) toàn bộ ứng dụng trong component QueryClientProvider và cung cấp một instance (đối tượng được khởi tại) của QueryClient.


import { QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Các thành phần của ứng dụng */}
    </QueryClientProvider>
  );
}

Bạn cũng có thể cung cấp các cấu hình mặc định cho QueryClient bằng cách truyền props vào hàm new QueryClient().


Sử dụng hooks của React-Query để thực hiện các yêu cầu HTTP

react-query hooks, useQuery hook, useMutation hook, sử dụng axios với react-query


Bắt đầu sử dụng React-Query trong các thành phần của ứng dụng của bạn. Bạn có thể sử dụng hook useQuery() để tải và quản lý dữ liệu từ server và hook useMutation() để thực hiện các thao tác thay đổi dữ liệu (update/delete).


useQuery

useQuery là một hook được cung cấp bởi thư viện React Query. React Query là một thư viện quản lý trạng thái dựa trên cache và tương tác mạng trong ứng dụng React.

useQuery được sử dụng để thực hiện các cuộc gọi mạng và truy vấn dữ liệu từ một nguồn dữ liệu bên ngoài, chẳng hạn như một API. Nó cho phép bạn định nghĩa một truy vấn (query) và tự động quản lý việc lấy dữ liệu, bộ nhớ cache, và cung cấp kết quả cho các thành phần React.


import { useQuery } from 'react-query';

const fetchMyData = async () => {
  const res = await fetch('/mydata');
  return res.json();
};
  
const MyComponent = () => {
  const { data, isLoading, error } = useQuery('myData', fetchMyData);


  if (isLoading) {
    return <div>Loading...</div>;
  }


  if (error) {
    return <div>Error: {error.message}</div>;
  }


  return <div>Data: {data}</div>;
}


Trong ví dụ trên, useQuery được sử dụng để gọi hàm fetchMyData để lấy dữ liệu từ một nguồn bên ngoài. Kết quả của truy vấn được lưu trữ trong biến data. Ngoài ra, isLoading được sử dụng để kiểm tra xem truy vấn đang trong quá trình tải và error dùng để xử lý lỗi nếu có.


Điều này chỉ là một ví dụ đơn giản về cách sử dụng useQuery trong React Query. Thư viện cung cấp nhiều tính năng và tùy chọn để quản lý trạng thái dữ liệu và tương tác mạng trong ứng dụng React. Ngoài ra useQuery còn rất nhiều data cũng như option đưa vào.

const {
	data,
	error,
	failureCount,
	isError,
	isFetchedAfterMount,
	isFetching,
	isIdle,
	isLoading,
	isPreviousData,
	isStale,
	isSuccess,
	refetch,
	remove,
	status
} = useQuery(key, fetcher);


useMutation

useMutation là một hook khác được cung cấp bởi thư viện React Query. Nó được sử dụng để thực hiện các thay đổi dữ liệu và gửi các yêu cầu mạng có tác động đến dữ liệu.

Khi sử dụng useMutation, bạn định nghĩa một hàm hoặc một callback để thực hiện thay đổi dữ liệu. Hook này sẽ cung cấp các hàm và trạng thái để quản lý quá trình mutation.

Dưới đây là một ví dụ về cách sử dụng useMutation trong React Query:

import { useMutation } from 'react-query';

const updateData = async (data) => {
  const res = await fetch('/mydata', {
     method: "POST",
     body: JSON.stringify(data),
  });
  return res.json();
};

const MyComponent = () => {
  const { mutate, isLoading, isError, error } = useMutation(updateData);


  const handleButtonClick = () => {
    mutate({ id: 1, name: 'New Name' });
  };


  if (isLoading) {
    return <div>Loading...</div>;
  }


  if (isError) {
    return <div>Error: {error.message}</div>;
  }


  return (
    <div>
      <button onClick={handleButtonClick}>Update Data</button>
    </div>
  );
};

Trong ví dụ trên, useMutation được sử dụng để gọi hàm updateData khi nút "Update Data" được nhấn. Khi mutation đang diễn ra, isLoading sẽ trả về true, cho phép bạn hiển thị một thông báo tải. Nếu có lỗi xảy ra trong quá trình mutation, isError sẽ trả về true và error sẽ chứa thông tin về lỗi.

useMutation cũng cung cấp các hàm như reset, revert, và onSuccess để quản lý quá trình mutation và xử lý kết quả thành công


Cách xử lý caching và refetching với React-Query để tối ưu hiệu năng ứng dụng

caching với react-query, refetching data với react-query, configure caching options in react query client

Để tối ưu hiệu năng ứng dụng với React-Query, bạn có thể sử dụng các tính năng caching và refetching được cung cấp bởi thư viện. Dưới đây là một số gợi ý để xử lý caching và refetching trong React-Query:

  1. Caching:
  • React-Query mặc định cung cấp caching cho các truy vấn. Khi bạn thực hiện một truy vấn, dữ liệu trả về từ yêu cầu trước đó sẽ được lưu trữ trong cache.
  • Để tận dụng caching, hãy sử dụng useQuery để thực hiện các truy vấn dữ liệu. React-Query sẽ tự động trả về dữ liệu từ cache nếu có sẵn và chỉ gửi yêu cầu mạng mới khi cần thiết.
  • Bạn có thể tuỳ chỉnh thời gian lưu trữ cache, xử lý invalidation cache khi dữ liệu thay đổi, và sử dụng các khái niệm như stale-while-revalidate để cải thiện hiệu suất.
  1. Refetching:
  • Khi dữ liệu trong cache đã cũ hoặc bạn muốn lấy phiên bản mới nhất, bạn có thể sử dụng chức năng refetching của React-Query.
  • Với useQuery, bạn có thể sử dụng hàm refetch để gửi lại yêu cầu mạng và cập nhật dữ liệu trong cache.
  • Bạn có thể kích hoạt refetching tự động theo khoảng thời gian nhất định bằng cách sử dụng thuộc tính refetchInterval hoặc refetchIntervalInBackground trong hook useQuery.
  1. Sử dụng tùy chọn khác:
  • React-Query cung cấp nhiều tùy chọn và thuộc tính để tùy chỉnh quá trình caching và refetching. Bạn có thể tìm hiểu thêm về các khái niệm như invalidateQueries, queryCache, queryKey, enabled, retry, và onSuccess để tùy chỉnh và điều khiển hiệu năng của ứng dụng.

Tuy nhiên để tối ưu hiệu năng chính xác cho ứng dụng của bạn, hãy xem xét các yêu cầu và tình huống cụ thể của bạn. Điều này cho phép bạn áp dụng các phương pháp caching và refetching phù hợp để đảm bảo hiệu suất tốt nhất và trải nghiệm người dùng tốt nhất trong ứng dụng của mình. Dưới đây là một ví dụ về việc sử dụng query key trong React-Query, hãy xem xét một trường hợp đơn giản: lấy danh sách người dùng từ một API.


import { useQuery } from 'react-query';


const UserList = () => {
  const { data, isLoading, isError, error } = useQuery('users', fetchUsers);


  if (isLoading) {
    return <div>Loading...</div>;
  }


  if (isError) {
    return <div>Error: {error.message}</div>;
  }


  return (
    <div>
      <h1>User List</h1>
      <ul>
        {data.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );import { QueryClient, QueryClientProvider } from 'react-query';


// Tạo một phiên bản mới của QueryClient
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      cacheTime: 300000, // Lưu trữ dữ liệu trong cache trong 5 phút (tính bằng mili giây)
      staleTime: 60000, // Coi dữ liệu là cũ sau 1 phút (tính bằng mili giây)
      refetchOnWindowFocus: false, // Tắt tự động refetch khi cửa sổ được focus
      retry: 3, // Thử lại truy vấn lỗi tối đa 3 lần
    },
    mutations: {
      throwOnError: true, // Throw error nếu mutation gặp lỗi
    },
  },
});

// Bao bọc ứng dụng của bạn bằng QueryClientProvider và cung cấp phiên bản queryClient
function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Các thành phần của ứng dụng */}
    </QueryClientProvider>
  );
}
};


async function fetchUsers() {
  const response = await fetch('/api/users');
  if (!response.ok) {
    throw new Error('Failed to fetch users.');
  }
  return response.json();
}


Trong ví dụ trên, chúng ta sử dụng useQuery để thực hiện truy vấn dữ liệu từ API. Tham số đầu tiên của useQuery là query key, được đặt là 'users'. Query key đại diện cho tên của truy vấn và sẽ được sử dụng để quản lý cache và refetching.

Khi fetchUsers được gọi, React-Query sẽ thực hiện yêu cầu mạng để lấy danh sách người dùng từ API. Nếu yêu cầu thành công, dữ liệu sẽ được trả về và hiển thị trong giao diện người dùng. Nếu có lỗi xảy ra, thông báo lỗi sẽ được hiển thị.

Khi query key thay đổi, React-Query sẽ tự động thực hiện refetching. Điều này có nghĩa là khi bạn thực hiện một hành động như cập nhật người dùng, query key sẽ thay đổi và React-Query sẽ tự động gửi lại yêu cầu mạng để cập nhật dữ liệu.


Để cấu hình các tùy chọn caching trong React Query client, bạn có thể sử dụng đối tượng queryClient và thiết lập các tùy chọn caching mong muốn. Dưới đây là một ví dụ về cách bạn có thể cấu hình các tùy chọn caching:

import { QueryClient, QueryClientProvider } from 'react-query';

// Tạo một phiên bản mới của QueryClient
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      cacheTime: 300000, // Lưu trữ dữ liệu trong cache trong 5 phút (tính bằng mili giây)
      staleTime: 60000, // Coi dữ liệu là cũ sau 1 phút (tính bằng mili giây)
      refetchOnWindowFocus: false, // Tắt tự động refetch khi cửa sổ được focus
      retry: 3, // Thử lại truy vấn lỗi tối đa 3 lần
    },
    mutations: {
      throwOnError: true, // Throw error nếu mutation gặp lỗi
    },
  },
});


// Bao bọc ứng dụng của bạn bằng QueryClientProvider và cung cấp phiên bản queryClient
function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Các thành phần của ứng dụng */}
    </QueryClientProvider>
  );
}


Trong ví dụ trên, chúng ta tạo một phiên bản mới của QueryClient và cung cấp các tùy chọn caching mong muốn trong thuộc tính defaultOptions. Dưới đây là một số tùy chọn caching thông dụng:

  • cacheTime: Xác định thời gian (tính bằng mili giây) mà dữ liệu sẽ được lưu trữ trong cache. Sau khoảng thời gian này, dữ liệu sẽ được coi là cũ và được refetch trong truy vấn tiếp theo.
  • staleTime: Xác định khoảng thời gian (tính bằng mili giây) sau đó dữ liệu đã cache sẽ được coi là cũ. Khi một truy vấn được hiển thị sau khoảng thời gian này, React Query sẽ tự động refetch dữ liệu trong nền và cập nhật cache.
  • refetchOnWindowFocus: Xác định liệu có nên tự động refetch dữ liệu khi cửa sổ được focus hay không. Đặt giá trị là true nếu bạn muốn dữ liệu được refetch khi cửa sổ được focus lại.
  • retry: Xác định số lần mà một truy vấn lỗi sẽ được thử lại trước khi được coi là lỗi. Bạn có thể đặt số lần thử lại cho cả truy vấn và mutations.
  • throwOnError: Xác định liệu mutation có nên throw error nếu gặp phản hồi lỗi hay không. Đặt giá trị là true nếu bạn muốn mutations mặc định throw error.


Với React-Query, bạn có khả năng tùy chỉnh việc caching dữ liệu, xử lý lỗi, tái thực hiện truy vấn và nhiều tính năng khác. Nó cung cấp một cách tiếp cận mạnh mẽ và linh hoạt để quản lý trạng thái dữ liệu trong ứng dụng React của bạn.

Với bài viết này, bạn đã có cái nhìn tổng quan về React-Query và cách sử dụng nó. Bằng cách tận dụng khả năng caching và tự động refetching của React-Query, bạn có thể xây dựng các ứng dụng React mạnh mẽ và hiệu quả hơn.