React Query 在處理即時更新快取(refetchOnWindowFocus + invalidate logs)

請 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)。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *