React Query 學(xué)習(xí) 1 概述及查詢

概述

React Query 時一個異步狀態(tài)管理庫,核心的概念有三個:

  1. 查詢(Queries)
  2. 修改(Mutations)
  3. 查詢錯誤處理(Query Invalidation)
import {
  useQuery,
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from "@tanstack/react-query";
import { getTodos, postTodo } from "../my-api";

// 創(chuàng)建一個 client
const queryClient = new QueryClient();

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

function Todos() {
  // 訪問 client
  const queryClient = useQueryClient();

  // 查詢
  const query = useQuery(["todos"], getTodos);

  // 修改
  const mutation = useMutation(postTodo, {
    onSuccess: () => {
      // 錯誤處理和刷新
      queryClient.invalidateQueries(["todos"]);
    },
  });

  return (
    <div>
      <ul>
        {query.data.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>

      <button
        onClick={() => {
          mutation.mutate({
            id: Date.now(),
            title: "Do Laundry",
          });
        }}
      >
        Add Todo
      </button>
    </div>
  );
}

render(<App />, document.getElementById("root"));

默認(rèn)配置

  • 默認(rèn)情況下,通過useQuery或useInfiniteQuery生成的查詢實例會將緩存的數(shù)據(jù)視為過時(stale)的。
  • 失敗的查詢將靜默重試 3 次,在捕獲并向 UI 顯示錯誤之前,會有指數(shù)級的后退延遲(exponential backoff delay)。

所謂指數(shù)級的后退延遲,是指每次重試時,會指數(shù)級增加等待時間,也即是指數(shù)級的降低訪問頻率。

要更改這一點,你可以將查詢的默認(rèn)retryretryDelay選項更改為3之外的其他值或指數(shù)后退函數(shù)。

  • 默認(rèn)情況下,查詢結(jié)果在結(jié)構(gòu)上是共享的,以檢測數(shù)據(jù)是否確實發(fā)生了更改。如果沒有,則數(shù)據(jù)的引用保持不變。

查詢 Queries

FetchStatus

在任何給定時刻,查詢只能處于以下狀態(tài)之一:

  • isLoading 或者 status === 'loading' - 查詢暫時還沒有數(shù)據(jù)
  • isError 或者 status === 'error' - 查詢遇到一個錯誤
  • isSuccess 或者 status === 'success' - 查詢成功,并且數(shù)據(jù)可用

除了status字段,result對象,還會有一個額外的fetchStatus屬性,它有以下選項:

  • fetchStatus === 'fetching' - 正在查詢中
  • fetchStatus === 'paused' - 查詢想要獲取,但它被暫停了。在網(wǎng)絡(luò)模式中閱讀更多相關(guān)信息
  • fetchStatus === 'idle' - 該查詢處于閑置狀態(tài)

為什么有兩種表示狀態(tài)的東西(status/fetchStatus)?

后臺刷新和數(shù)據(jù)過期重試(stale-while-revalidate)的邏輯使statusfetchStatus的所有組合成為了可能。比如說:

  • 一個state='success'的查詢通常處于fetchStatus='idle'狀態(tài)。但如果同時有后臺重新獲取動作,它也可能為fetchStatus='fetching'狀態(tài)。
  • 一個沒有數(shù)據(jù)的查詢通常處于status='loading'狀態(tài)和fetchStatus='loading狀態(tài)。如果同時無網(wǎng)絡(luò)連接,它也可能為fetchStatus='paused'狀態(tài)。

所以請記住,一個查詢可以處于fetchStatus='loading'狀態(tài),但沒有實際的在獲取數(shù)據(jù)。 如何理清兩者關(guān)系?這里有一個簡單的經(jīng)驗法則:

  • status告訴我們有關(guān)data的狀態(tài):有或者沒有?
  • fetchStatus告訴我們有關(guān)queryFn的狀態(tài):在執(zhí)行還是沒在執(zhí)行?

有效的使用 React Query Keys

https://tkdodo.eu/blog/effective-react-query-keys

查詢鍵值是 hash 決定的!

這意味著,不管對象中鍵值的順序如何,以下所有查詢都被認(rèn)為是相等的:

useQuery(['todos', { status, page }], ...);
useQuery(['todos', { page, status }], ...);
useQuery(['todos', { page, status, other: undefined }], ...);

但是,以下查詢鍵值不相等。這些數(shù)組項的順序很重要,因為它們的散列信息并不相同!

useQuery(['todos', status, page], ...);
useQuery(['todos', page, status], ...);
useQuery(['todos', undefined, page, status], ...);

useQuery 和 useInfiniteQuery 共享緩存,不能使用同樣的 key。因為兩種數(shù)據(jù)請求結(jié)構(gòu)不同。

useQuery(['todos'], fetchTodos)

// ?? this won't work
useInfiniteQuery(['todos'], fetchInfiniteTodos)

// ? choose something else instead
useInfiniteQuery(['infiniteTodos'], fetchInfiniteTodos)

如果查詢依賴變量,把他們放在 Query Key 中

function Todos({ todoId }) {
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  })
}

自動重取數(shù)據(jù)

function Component() {
  const [filters, setFilters] = React.useState()
  const { data } = useQuery(['todos', filters], () => fetchTodos(filters))

  // ? set local state and let it "drive" the query
  return <Filters onApply={setFilters} />
}

setFilter 會導(dǎo)致發(fā)送給 useQuery 的 Query Key 不同。從而觸發(fā)重取數(shù)據(jù)。導(dǎo)致 data 的變化從而重繪組件。

Colocation 共處

參照 Maintainability through colocation。
Queries 和 組件應(yīng)該共處在同一個功能下面,即還是應(yīng)該按照功能 / 組織代碼。關(guān)聯(lián)的代碼在相同的地方更有利于代碼的管理。代碼分層和抽象會導(dǎo)致關(guān)聯(lián)性降低,導(dǎo)致代碼維護(hù)性降低。

- src
  - features
    - Profile
      - index.tsx
      - queries.ts
    - Todos
      - index.tsx
      - queries.ts

結(jié)構(gòu)

將Query Key 按照從寬泛到獨有安排。例如

['todos', 'list', { filters: 'all' }]
['todos', 'list', { filters: 'done' }]
['todos', 'detail', 1]
['todos', 'detail', 2]

使用 Query Key Factory

使用 factory 管理 Query Key 的關(guān)聯(lián)性

const todoKeys = {
  all: ['todos'] as const,
  lists: () => [...todoKeys.all, 'list'] as const,
  list: (filters: string) => [...todoKeys.lists(), { filters }] as const,
  details: () => [...todoKeys.all, 'detail'] as const,
  detail: (id: number) => [...todoKeys.details(), id] as const,
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容