Skip to content

初探 React Query

Posted on:February 8, 2023 at 02:08 PM

Table of contents

Open Table of contents

前言

在公司內部的分享會中,分享了 React Query 的使用方法。在這裡將他整理成文章,方便之後遇到問題可以複習。

介紹

什麼是 React Query

React Query 是什麼? 在官方文件的第一頁寫了

React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your React applications a breeze.

所以可以知道的是,React 本身缺少了 data fetching 的工具,而 React Query 可以彌補這件事情。

用比較技術性的話語來講,React Query 可以 “輕鬆” 的達成 fetching、caching、synchronizing 與 updating server state 這些功能。

當我們搜尋 React Query 的時候,會出現以下兩種文件。

在 2022 年的 7 月,React Query 推出的第四個版本。並稱為 TankStack Query。

左邊是 v3 右邊是 v4 的文件。

docs

那麼會有這個改動,是因為他想要遵循 Framework Agnostic 這個規範。

Framework Agnostic

Framework Agnostic 的意思是,工具不依賴特定的框架或平台,可以在多個環境中運行。它可以讓開發者選擇適合他們的框架,而不是被限制於特定的框架。就

像原本的 react query 他只能在 react 中使用。改名叫 tankquery 後,官方文件的左側就可以選擇其他的框架,目前也支援 Vue、Svelte、Solid 這三個框架。

那麼也遵循 Framework Agnostic 的工具,還包括了 vite 跟 typescript。

v3 與 v4 的差異

文件裡面提及非常多的更新,那這邊我紀錄文件中的前四項更新。

第一個更新就是 import 的改變

React Query v4 Update 1

第二的更新就是 query key 變成只能帶入 array,在 v3 中是可以帶入 string 或是 array。

React Query v4 Update 2

第三個更新是 status: idle 在 v4 中就將他移除,原因是因為在 v4 中新增了 fetchStatus 的參數。

所以目前 status 只有三個狀態。

fetchStatus 也只有三種

React Query v4 Update 3

第四個更新是可以使用 useQueries 這個參數,可以一次打多個 api 。

React Query v4 Update 4

使用方法

QueryClient

在整個專案的進入點 (ex. src/index.js) 加上

import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,
      refetchOnReconnect: false,
    },
  },
});

function App() {
  return (
    <QueryClientProvider client={queryClient} contextSharing={true}>
      <Todos />
    </QueryClientProvider>
  );
}

useQuery

useQuery 可以有很多種寫法,這邊我大致分為三種。

寫法一跟二是透過解構,進而取得 data 跟 status。

寫法三是透過宣告變數,再使用變數取存取值。

個人會比較推薦寫法三,因為當一個頁面要發多個 api 時,data 就會出現命名衝突。大多時候都還需要重新命名,所以不如一開始就宣告變數,就可以省去很多麻煩,程式碼也會更好閱讀。

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

function App() {
  const getPostFn = () =>
    axios.get("http://localhost:8888/posts").then(res => res.data);

  // 寫法一
  const { isLoading, error, data, isFetching, refetch } = useQuery({
    queryKey: ["post"],
    queryFn: getPostFn,
  });

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

  // 寫法二
  const { status, data } = useQuery({
    queryKey: ["post"],
    queryFn: getPostFn,
  });

  if (status === "isLoading") {
    return "isLoading...";
  }

  // 寫法三
  const post = useQuery({
    queryKey: ["post"],
    queryFn: () => getPostFn(),
  });

  if (post.isLoading) {
    return "Loading...";
  }
}

useMutation

import { useMutation } from "@tanstack/react-query";
function App() {
  const postFn = newPost => axios.post("http://localhost:8888/posts", newPost);

  const mutation = useMutation({
    mutationFn: postFn,
    onSuccess: () => {
      // useQuery
      refetch();
    },
  });

  return (
    <>
      {mutation.isError ? (
        <div>An error occurred: {mutation.error.meesage}</div>
      ) : null}

      {mutation.isSuccess ? <div>Post added!</div> : null}

      <button
        onClick={() => {
          mutation.mutate({ id: crypto.randomUUID(), title: "test" });
        }}
      ></button>
    </>
  );
}

比較

接下來會談一些 api 的比較,避免再開發的時候誤用。

status vs fetchStatus

cacheTime vs staleTime

如果想要 data 保持最新,可以設置較短的 staleTime,並且在過期之後立即重新發出請求以獲取最新 data。

如果我們要保持最大的緩存使用效率,則可以設置較長的 cacheTime 以保留 data 在緩存中較長的時間。

設置好 cacheTimestaleTime 的優點是,在請求之後可以大大減少 API 的請求次數,減少 request,提高頁面加載速度,避免頁面一直出現 Loading 的樣式,提高使用者體驗。