React Query 緩存更新的陷阱:不可變性是關鍵
在 React 開發中,處理伺服器狀態是一大挑戰。React Query 作為一個強大的工具,簡化了資料獲取、緩存和更新的流程。然而,在使用 setQueryData 更新緩存時,存在一個容易被忽略的陷阱:不可變性。
事件開頭短結論:使用 setQueryData 更新 React Query 緩存時,務必確保以不可變的方式修改資料,避免直接修改 oldData 或從緩存中獲取的資料,否則可能導致難以察覺的錯誤。
事件重點:
- 不可變性是核心:React Query 強調緩存更新的不可變性。
- 避免直接修改:不要直接修改從緩存中獲取的資料。
- 使用更新函數:利用更新函數,傳入當前資料,返回新的資料,進行更新。
為什麼不可變性如此重要?
想像一下,你正在開發一個待辦事項清單應用程式。當用戶編輯一項任務時,你可能會使用 setQueryData 來更新快取中的資料。如果直接修改了緩存中的資料,React Query 無法正確偵測到這些變化。雖然畫面看起來似乎更新了,但實際上可能會出現各種問題,例如:
- UI 未正確更新:React Query 無法重新渲染使用該資料的元件。
- 潛在的錯誤:資料的狀態可能與後端不一致,導致不可預測的行為。
如何以不可變的方式更新緩存?
React Query 提供了幾種方法來確保緩存更新的不可變性:
- 使用更新函數:
setQueryData接受一個更新函數作為參數。這個函數接收當前的資料(oldData),你可以在這個函數中根據oldData產生新的資料,然後返回它。這樣 React Query 就能夠正確地偵測到變化,並更新 UI。queryClient.setQueryData(['todos'], (oldData) => { // oldData 為舊的資料,你需要根據它產生新的資料 return oldData.map(todo => todo.id === updatedTodo.id ? updatedTodo : todo ); }); - 使用擴展運算符(…):當你只需要修改資料的某個部分時,可以使用擴展運算符來創建新的物件或陣列。
queryClient.setQueryData(['posts', { id: 1 }], (oldData) => ({ ...oldData, title: '新的標題' }));
個人心得:
在 React 開發中,不可變性是一個重要的原則。尤其是在使用 React Query 這樣的狀態管理庫時,更要嚴格遵守。雖然直接修改快取資料看似方便,但卻容易引入難以排查的錯誤。使用更新函數和擴展運算符,雖然需要多寫一些程式碼,但卻能確保你的應用程式的穩定性和可靠性。
總結
在 React Query 中,不可變性是確保緩存更新正確的關鍵。通過使用更新函數和擴展運算符,我們可以避免直接修改快取資料,從而創建更穩定、更容易維護的應用程式。記住,遵守不可變性原則,可以讓你避免許多潛在的錯誤,並提高開發效率。
參考閱讀
- https://github.com/TanStack/query/discussions/4962
- https://tanstack.com/query/v4/docs/reference/QueryClient
- https://www.answeroverflow.com/m/1387458645293269053
- https://stackoverflow.com/questions/72078510/mutate-previous-data-in-setquerydata