Back to Blog
聊聊 TanStack Query:為什麼它讓我重新思考前端狀態管理
📝 Dev Notes

聊聊 TanStack Query:為什麼它讓我重新思考前端狀態管理

B
Blake
Oct 27, 2025 By Blake 8 min read
你是否也被 Redux 裡滿滿的 API 處理邏輯搞得頭很大?是否懷疑過為什麼一個簡單的資料請求需要寫 50 行程式碼? 這篇文章源自我在重構專案時的頓悟:我們一直在用錯誤的方式管理伺服器狀態。透過 TanStack Query,我重新理解了前端狀態管理的本質 - 不是所有狀態都該用同一種方式處理。 文章涵蓋: 為什麼要區分伺服器狀態和本地狀態 React/Vue 專案的最佳實踐架構 TanStack Query 的核心優勢(程式碼量減少 90%!) 實際的程式碼對比和遷移經驗 效能優化技巧和踩坑分享 無論你是 React 還是 Vue 開發者,這篇文章都能幫你找到更優雅的狀態管理方案。最重要的是,你會學到如何讓每個工具在最適合的場景發揮作用,而不是試圖用一個工具解決所有問題。

最近重構了幾個專案,發現一個有趣的現象:我們團隊寫的 Redux 程式碼裡,大概有七成都在處理 API 相關的邏輯。這讓我開始思考,是不是有更好的方式來管理這些資料?

後來接觸到 TanStack Query,才發現原來問題出在我們把所有東西都當成「狀態」來處理。其實仔細想想,從伺服器來的資料和本地的 UI 狀態,本質上就是完全不同的東西。

為什麼要區分伺服器狀態和本地狀態?

先說說什麼是伺服器狀態吧。簡單來說,就是那些存在後端資料庫、需要透過 API 取得的資料。這類資料有幾個特點讓它們很難搞:

  • 你永遠不知道什麼時候會被其他人改掉

  • 每次要用都得發請求,還要處理載入和錯誤狀態

  • 要考慮快取,不然用戶體驗會很差

  • 網路斷了要重試,資料過期要更新

而本地狀態就單純多了,像是 modal 開關、表單輸入、使用者選的主題顏色這些,完全在前端控制,不需要跟後端打交道。

我以前的做法是把這兩種狀態都塞進 Redux 裡管理,結果寫了一堆 action 和 reducer 來處理 API 請求。現在回頭看,真的是自找麻煩。

在 React 專案裡怎麼分工?

經過這幾年的實戰,我現在的做法是這樣:

簡單的元件狀態就用 useState,不要想太多。比如一個下拉選單的開關狀態,用 useState 就夠了,搞個 Redux 反而是過度設計。

需要跨元件共享的狀態才考慮 Redux 或 Zustand。說實話,現在我更偏好 Zustand,因為它的 API 簡單多了,不像 Redux 要寫一堆 boilerplate。不過如果專案已經用 Redux 了,而且大家都熟悉,那就繼續用也沒問題。

所有 API 相關的資料交給 TanStack Query。這真的是改變遊戲規則的工具,它幫你處理了所有麻煩事:快取、重試、背景更新、loading 狀態...你能想到的都有。

Vue 專案也是一樣的道理

Vue 生態系統其實也面臨同樣的問題。我有朋友的 Vue 專案,Vuex 裡面一大堆處理 API 的程式碼,看得頭都大了。

現在 Vue 3 有了 Composition API,處理本地狀態變得更簡單。全域狀態的話,Pinia 是新的推薦選擇(比 Vuex 好用太多了)。而伺服器狀態?一樣用 TanStack Query 的 Vue 版本。

有意思的是,很多人擔心用了 TanStack Query 會不會和 Pinia 衝突。其實完全不會,它們各司其職:Pinia 管理你的業務邏輯和 UI 狀態,TanStack Query 專門處理 API 資料。

TanStack Query 到底好在哪?

程式碼少得驚人

我來給你看個對比。以前用 Redux 處理一個簡單的 todo list API:

// 要寫 action
export const fetchTodos = () => async (dispatch) => {
  dispatch({ type: 'FETCH_TODOS_REQUEST' })
  try {
    const response = await fetch('/api/todos')
    const data = await response.json()
    dispatch({ type: 'FETCH_TODOS_SUCCESS', payload: data })
  } catch (error) {
    dispatch({ type: 'FETCH_TODOS_FAILURE', error })
  }
}

// 還要寫 reducer
const todosReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_TODOS_REQUEST':
      return { ...state, loading: true }
    case 'FETCH_TODOS_SUCCESS':
      return { ...state, loading: false, data: action.payload }
    case 'FETCH_TODOS_FAILURE':
      return { ...state, loading: false, error: action.error }
    default:
      return state
  }
}

// 使用的時候還要 dispatch
useEffect(() => {
  dispatch(fetchTodos())
}, [])

現在用 TanStack Query:

const { data, isPending, error } = useQuery({
  queryKey: ['todos'],
  queryFn: () => fetch('/api/todos').then(r => r.json()),
})

就這樣,沒了。而且功能還更強大,自動幫你處理重試、快取、背景更新...

快取機制超聰明

TanStack Query 的快取真的很聰明。你設定好 staleTimecacheTime,它就知道什麼時候該重新請求,什麼時候可以直接用快取。

更酷的是,如果多個元件同時請求相同的資料,它會自動合併成一個請求。使用者切換頁面再回來,資料還在,但如果太久沒用,它會在背景悄悄更新。這些如果要自己實現,程式碼量可不少。

樂觀更新讓體驗更好

你知道什麼最影響用戶體驗嗎?就是按下按鈕後要等個一兩秒才看到結果。TanStack Query 的樂觀更新可以讓 UI 立即響應,然後在背景處理真正的請求。如果請求失敗了,它會自動回滾,用戶甚至不會察覺。

我在做一個即時協作的專案時,這個功能救了我一命。用戶的每個操作都能立即看到效果,體驗好太多了。

什麼時候用什麼工具?

經過這段時間的使用,我總結了一些經驗:

需要 TanStack Query 的場景:

  • 專案大量依賴後端 API(廢話,現在哪個不是)

  • 需要實現無限滾動、分頁這類功能

  • 多個元件要共享同一份伺服器資料

  • 對用戶體驗要求高,需要樂觀更新

還是需要 Redux/Pinia 的場景:

  • 複雜的多步驟表單(每一步的資料要暫存)

  • 全域的 UI 狀態(通知系統、主題設定)

  • 需要 time-travel 除錯功能

  • 團隊已經很熟悉 Redux,而且用得好好的

說實話,大部分專案兩個都需要。我現在的標準配置是:本地狀態用框架自帶的(useState、Composition API),業務邏輯用 Redux/Pinia,API 資料用 TanStack Query。

從 Redux 遷移的一些建議

如果你正在考慮遷移,我的建議是不要一次全換。可以先在新功能上試用 TanStack Query,感受一下差異。等團隊熟悉了,再逐步遷移舊程式碼。

遷移過程中你會發現,原本一大堆的 Redux 程式碼可以刪掉了。我們有個專案,遷移後程式碼量減少了將近 40%,而且功能還更強大了。

效能優化的小細節

TanStack Query 在效能優化上做了很多工作:

請求去重是我最喜歡的功能之一。假設你有三個元件同時 mount,都需要用戶資料,TanStack Query 只會發一個請求,然後把結果分享給三個元件。

結構共享也很巧妙。當資料更新時,沒變的部分會保持相同的引用,這樣可以避免不必要的重新渲染。配合 React.memo 使用效果很好。

預取功能可以讓你在用戶點擊前就載入資料。比如用戶 hover 在連結上時就開始載入,點進去就能立即看到內容。

一些實際使用的坑

當然,沒有工具是完美的。使用 TanStack Query 也踩過一些坑:

  1. 快取 key 的設計要想清楚。如果設計不好,會導致快取失效或者資料不同步。

  2. 不要什麼都快取。有些資料真的不需要快取,比如即時股價、線上人數這種。

  3. 錯誤處理要做好。雖然 TanStack Query 提供了錯誤重試,但有些錯誤(比如 401)不應該重試。

總結

TanStack Query 不是銀彈,它不能解決所有狀態管理的問題。但在處理伺服器狀態這件事上,它確實是目前最好的選擇之一。

最重要的是理解不同類型的狀態需要不同的處理方式。不要試圖用一個工具解決所有問題,那樣只會讓架構變得複雜難維護。

如果你還在用 Redux 處理所有的 API 請求,真的建議試試 TanStack Query。相信我,一旦用過就回不去了。

Enjoyed this article? Show some love!

0
Clap

Enjoyed this article?

Subscribe for engineering notes and AI development insights

We respect your privacy. No spam, unsubscribe anytime.

Share this article

Comments