iT邦幫忙

2024 iThome 鐵人賽

DAY 12
0
Modern Web

前進React 生態系 : 技術應用與概念解析系列 第 12

Day 12 - 掌握 Server State:為何你需要 Server State 管理與 React Query 的簡介

  • 分享至 

  • xImage
  •  

使用 useEffect 和 useState fetch 資料的問題

在 React 開發中,我們經常會從伺服器端取得資料,通常會使用 useEffect 搭配 useState 來 fetch 資料。然而,這種方式雖然可以解決問題,但有可能會遇到以下問題:

  1. 更多的狀態管理: 除了取得資料,還需要處理 loading 和 error 的狀態,需要額外寫狀態 。
  2. Race Condition : 一個 component 發出多次相同的請求,可能會以不預期的順序返回。雖然可以通過加上條件判斷或使用 AbortController 來解決,但這會增加程式的複雜性。
  3. 多個 Component 重複請求同一筆資料 : 會導致資源浪費和增加使用者的等待時間,為了避免此問題,需要建立快取。
  4. 資料同步和過期處理 : 資料可能會隨時間而變更,當資料過時時需要重新發送 API 請求來獲取最新的資料,需要額外處理資料同步與過期策略,

還有其他許多可能遇到的問題,可以想像如果這些問題都要處理,需要寫很多的程式碼,導致邏輯很複雜。

Server State Management 的優勢

這時候使用 Server State Management 的套件就能有效解決以上問題。不只是單純處理 fetch 和 state 管理,這些 library 通常還能提供快取、資料同步、背景更新等功能。

  • 簡化程式碼:大幅減少需要處理的邏輯,使得程式碼更為清晰可維護。
  • 建立快取:透過 stale-while-revalidate,能夠在保持資料的新鮮度的同時,提供更快的資料存取。
  • 資料同步:自動處理資料的更新,確保使用者隨時獲得最新的資訊,提升使用體驗。
  • 提高效能:提高效能,讓使用者體驗更佳。

Server State Management 套件介紹

  • React Query : 功能最豐富也是最熱門的套件。
  • RTK Query (redux toolkit query) : 如果已經使用 Redux Toolkit,那麼 RTK Query 是一個不錯的選擇,因為不需要在額外安裝任何套件。
  • SWR : 由 Vercel 推出,功能比較簡單,比較適合中小型的應用。

細節的比較可以參考 這裡。基本上概念都是類似的,有部份功能上細節的差異,主要介紹會是以 React Query 為主。

React Query 基礎使用介紹

安裝和設定

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

const queryClient = new QueryClient();

export function App({ children }) {
  return (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
}

useQuery

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

export default function UserList() {
  const { data, error, isLoading } = useQuery({
    queryKey: ["users"], 
    queryFn: fetchUserData,
  });

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

  return (
    <div>
      <h1>User Data</h1>
      <div>
        {data.map((user) => (
          <div key={user.id}>
            <p>Name: {user.name}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

queryKey : 會是一個陣列,可以用 sting 或是複雜結構的 array,只要是可序列化並且是唯一的,用來管理快取。
queryFn : 可以是返回 Promise 的任何函數,用來定義如何獲取數據

主要架構會長這樣,除此之外 useQuery 也有其他選項來設定:

  • refetchOnWindowFocus : 設定當瀏覽器視窗重新取得焦點時,是否自動重新抓取資料,預設為 true
  • refetchInterval: 設定每隔幾秒重新獲取資料。
  • enable: 設定是否啟用這次資料請求,在某些條件滿足時才發送 API 請求。
  • gcTime(之前叫 cacheTime) : 新鮮資料的維持時間,過期後的任何新請求,都會重新獲取,預設 0 秒。
  • staleTime : 設定快取資料在不再被使用後,多久會被自動刪除,通常會設置得比 staleTime 大,預設 5 分鐘。

除了在 useQuery 設定,也可以在 QueryClient 設定 defaultOptions

這些設定將應用於所有 useQuery,除非在單獨的 useQuery 中覆蓋這些值。

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5000,
      gcTime: 300000,
      refetchOnWindowFocus: false,
      //...
    },
  },
});

useMutation

import { addUser } from "./api";
import { useMutation, useQueryClient } from "@tanstack/react-query";

export default function AddUser() {
  const queryClient = useQueryClient();
  const mutation = useMutation({
    mutationFn: addUser,
    //當 mutation 成功後執行
    onSuccess: () => {
      //告知 React Query queryKey 無效並重新取得資料
      queryClient.invalidateQueries({ queryKey: ["users"] });
    },
  });

  return (
    <button onClick={() => mutation.mutate({ id: Date.now(), name: "John" })}>
      Add User
    </button>
  );
}

參考資料:
https://tkdodo.eu/blog/why-you-want-react-query
https://www.youtube.com/watch?v=OrliU0e09io
https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect
https://tanstack.com/query/latest/docs/framework/react/overview
https://tanstack.com/query/latest/docs/framework/react/guides/caching#basic-example


上一篇
Day 11 - Zustand 原理解析
下一篇
Day 13 - React Query 原理解析
系列文
前進React 生態系 : 技術應用與概念解析30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言