請 AI 在寫程式, 順便學一下 React 怎麼更新快取, 這個異動之前, 需要使用者手動 reload page 才能取得正確資訊.
await queryClient.invalidateQueries({ queryKey: ['/api/suggestions/'], exact: false });
// Use predicate because the key is a single string '/api/suggestions/{id}/logs'
// and partial array prefix matching would not reach it.
await queryClient.invalidateQueries({
predicate: (query) =>
typeof query.queryKey[0] === 'string' &&
(query.queryKey[0] as string).endsWith('/logs'),
});
// The detail page may already be open (same SPA), so refetchOnWindowFocus won't fire.
await queryClient.invalidateQueries({ queryKey: ['/api/suggestions/'], exact: false });
await queryClient.invalidateQueries({
predicate: (query) =>
typeof query.queryKey[0] === 'string' &&
(query.queryKey[0] as string).endsWith('/logs'),
});
上面的紅色刪除 code, 綠色是新增的 code.
這段程式碼之所以能達成即時更新快取,關鍵在於它修正了 TanStack Query (React Query) 的快取清除機制,從原本失效的「前綴匹配」改為精準的「條件篩選」。
以下為您詳細拆解它的運作原理,以及快取內容是如何重新取得的:
1. 為什麼這樣子做,可以即時更新快取?
在原先的程式碼中,開發者試圖使用以下方式來讓快取失效:
TypeScript
// 舊寫法:無效
await queryClient.invalidateQueries({ queryKey: ['/api/suggestions/'], exact: false })
為什麼舊寫法會失敗?
React Query 在處理 queryKey 陣列時,預設的模糊匹配(exact: false)是比對陣列中的元素元素(Array Elements)。
如果你的 API 快取鍵值(Query Key)在設計時是一個單一字串(例如:'/api/suggestions/{id}/logs'),React Query 會認為這個陣列裡只有一個元素。它在比對時,會檢查 '/api/suggestions/{id}/logs' 是否「完全等於」或「為陣列前綴」,但它不會去把字串拆開做子字串匹配。因此,舊寫法完全找不到對應的快取,自然無法更新。
為什麼新寫法(Predicate)可以成功?
新程式碼改用 predicate 自訂篩選函式:
TypeScript
// 新寫法:成功
await queryClient.invalidateQueries({
predicate: (query) =>
typeof query.queryKey[0] === 'string' &&
(query.queryKey[0] as string).endsWith('/logs'),
})
- 主動巡檢:
predicate就像是一個過濾器,它會遍歷目前瀏覽器記憶體中所有現存的 React Query 快取。 - 精準識別:不論
{id}是多少(例如/api/suggestions/123/logs或/api/suggestions/456/logs),只要快取鍵值的第 0 個元素是字串,且結尾是'/logs',就會被強制貼上「已過期(Stale)」的標籤。
透過這種方式,所有相關的審核紀錄快取(Suggestion Logs)就會在代理人變更的當下立刻失效,迫使畫面準備更新。
2. 快取內容又是如何去取得(重新發送請求)?
當 invalidateQueries 成功將這些快取標記為「已過期(Stale)」後,React Query 會根據當前頁面的狀態,自動透過以下邏輯去重新取得(Refetch)最新的資料:
狀況 A:該資料正顯示在當前畫面上(作用中的 Query)
如果使用者正停留在該審核紀錄的頁面上(該 Query 處於 active 狀態),一旦 invalidateQueries 被執行,React Query 會立刻在背景自動觸發對應的 API 請求(例如呼叫後端後台 GET /api/suggestions/{id}/logs),取得最新含有新代理人資訊(approvalProgress.reviewer_delegate_id)的資料,並在收到回應後即時渲染、更新畫面。
狀況 B:該資料目前沒顯示在畫面上(非作用中的快取)
如果使用者目前在其他分頁,這些被標記為過期的快取會先靜靜地待在記憶體中。直到使用者切換回該詳細頁面、畫面重新掛載(Mount)該元件時,React Query 偵測到「快取已過期」,就會在初始化時立刻發送 API 請求撈取最新資料,確保使用者看到的絕對不會是舊代理人的髒資料(Dirty Data)。