Effective React Query Keys
Query Keys 是 React Query 的核心概念之一。它們讓函式庫能正確快取資料、在依賴變動時自動 refetch,還能讓你在需要時手動操作 Query Cache,例如 mutation 後更新資料或手動失效某些查詢。
在介紹我自己如何組織 Query Key 之前,先快速說明這三個重點的意義。
資料快取
Query Cache 其實就是一個 JavaScript 物件,key 是序列化後的 Query Key,value 則是查詢資料加上一些 meta 資訊。key 會用確定性 hash 處理,所以你也可以用物件當 key(但最外層還是要是字串或陣列)。
最重要的是 key 必須對每個查詢唯一。React Query 只要在 cache 找到 key,就會直接用。注意:不能用同一個 key 同時給 useQuery
跟 useInfiniteQuery
,因為只有一個 Query Cache,兩者會共用資料,這會出問題,因為 infinite query 跟一般 query 結構完全不同。
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
// 🚨 這樣不行
useInfiniteQuery({
queryKey: ['todos'],
queryFn: fetchInfiniteTodos,
})
// ✅ 請用不同 key
useInfiniteQuery({
queryKey: ['infiniteTodos'],
queryFn: fetchInfiniteTodos,
})
自動 refetch
Queries 是宣告式的。
這個觀念非常重要,值得一再強調,而且一開始很難「開竅」。大多數人會用命令式思維看待查詢與 refetch。
我有一個查詢,抓到資料。現在我按按鈕想 refetch,但參數不同。很多人會這樣寫:
// imperative-refetch
function Component() {
const { data, refetch } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
// ❓ refetch 怎麼帶參數?
return <Filters onApply={() => refetch(???)} />
}
答案是:你不用這樣做。
refetch
只會用同一組參數重新抓資料。
如果你有會影響查詢的 state,只要把它放進 Query Key,React Query 會自動在 key 變動時 refetch。所以要套用篩選條件,只要改變 client state:
// query-key-drives-the-query
function Component() {
const [filters, setFilters] = React.useState()
const { data } = useQuery({
queryKey: ['todos', filters],
queryFn: () => fetchTodos(filters),
})
// ✅ 改 local state 就會自動 refetch
return <Filters onApply={setFilters} />
}
setFilters
會觸發 re-render,新的 Query Key 傳給 React Query,就會自動 refetch。更深入例子可參考 practical react query#treat the query key like a dependency array。