測驗:React + TanStack 架構總覽
共 5 題,點選答案後會立即顯示結果
1. 判斷是否需要 SSR 的核心標準是什麼?
2. 在 React + TanStack 的架構中,TanStack Query 負責的是哪一層的工作?
3. 文章提到 Next.js 的「Vendor Lock-in」問題,這指的是什麼?
4. 看到以下程式碼,queryKey 的作用是什麼?
5. 你正在開發一個需要登入才能使用的專案管理 SaaS 應用,AI 建議使用 Next.js。根據文章的分析,以下哪個判斷最合理?
一句話說明
用 React + TanStack 建構純前端 SPA,不用全端框架也能搞定路由和資料管理。
這篇在講什麼
如果你用 AI 幫你寫 React 專案,AI 可能會建議你用 Next.js。但很多時候,你的專案根本不需要 SSR(伺服器端渲染)。這篇文章幫你搞懂:什麼時候用純前端就夠了,以及為什麼 React + TanStack 是一套務實的選擇。
前置知識
- 基本的 React 開發經驗(知道 component、props、hooks)
- 知道什麼是 SPA(Single Page Application)
SPA vs SSR:什麼時候純前端就夠了?
先搞懂兩種渲染方式
SPA(純前端) SSR(伺服器端渲染)
┌─────────────┐ ┌─────────────┐
│ 瀏覽器下載 JS │ │ 伺服器先產出 HTML │
│ JS 在瀏覽器跑 │ │ 傳給瀏覽器顯示 │
│ 畫面都在前端產生│ │ 再載入 JS 互動 │
└─────────────┘ └─────────────┘
白話翻譯:
- SPA:瀏覽器下載一包 JavaScript,所有畫面切換都在瀏覽器端完成,不用每次都問伺服器要新的頁面。
- SSR:每次切換頁面,伺服器先把 HTML 組好再傳過來,搜尋引擎看得到完整內容。
什麼時候 SPA 就夠了?
| 場景 | 需要 SSR? | 原因 |
|---|---|---|
| 登入後的 Dashboard | 不需要 | 搜尋引擎不會爬登入後的頁面 |
| 內部管理工具 | 不需要 | 只有內部員工用,不需要 SEO |
| SaaS 應用的前台 | 不需要 | 登入後才能用,不需要被搜尋 |
| 部落格 / 行銷官網 | 需要 | SEO 是流量來源 |
| 電商產品頁 | 需要 | 商品要被 Google 搜到 |
判斷標準很簡單:**你的頁面需要被搜尋引擎找到嗎?** 不需要的話,SPA 就夠了。
為什麼不直接用 Next.js?
AI 很喜歡推薦 Next.js,但它不一定適合你的專案。來看三個常見的「過度工程化」陷阱:
陷阱 1:部署複雜度
Next.js 部署 純前端 SPA 部署
┌──────────────┐ ┌──────────────┐
│ 需要 Node.js 伺服器 │ │ 丟上任何靜態檔案伺服器│
│ 或用 Vercel 託管 │ │ Netlify / S3 / 任何CDN│
│ 有 serverless 冷啟動│ │ 零伺服器成本 │
└──────────────┘ └──────────────┘
SPA 只是一堆靜態檔案(HTML + JS + CSS),丟到任何地方都能跑。Next.js 則需要一個 Node.js 伺服器處理 SSR。
陷阱 2:你不需要的功能在增加複雜度
// Next.js 的 Server Component —— 如果你不需要 SSR,這些都是多餘的
// app/dashboard/page.tsx
export default async function DashboardPage() {
const data = await fetch('https://api.example.com/stats') // 伺服器端抓資料
return <Dashboard data={data} />
}
// ↑ 看起來簡單,但背後牽涉到:伺服器環境、快取策略、revalidation...
Code language: JavaScript (javascript)// 純前端做法 —— 直覺、單純
function DashboardPage() {
const { data } = useQuery({ queryKey: ['stats'], queryFn: fetchStats })
return <Dashboard data={data} />
}
// ↑ 所有邏輯都在瀏覽器端,你看得到、除得了錯
Code language: JavaScript (javascript)陷阱 3:Vendor Lock-in
Next.js 和 Vercel 深度綁定。雖然可以自己部署,但很多優化功能(Image Optimization、ISR 等)在非 Vercel 環境會受限。純前端 SPA 則沒有這個問題——你可以部署到任何地方。
什麼時候該用 Next.js?
別誤會,Next.js 是很好的框架。如果你的專案符合以下條件,它仍然是好選擇:
- 需要 SEO(部落格、電商、行銷頁面)
- 需要在伺服器端處理敏感邏輯(API key 不能暴露在前端)
- 團隊已經熟悉 Next.js 生態系
但如果你做的是 Dashboard、內部工具、或登入後才能用的 SaaS,純前端通常是更簡單的選擇。
TanStack 生態系:各自解決什麼問題?
選擇純前端之後,你需要解決兩個核心問題:頁面怎麼切換和資料怎麼管理。這正是 TanStack Router 和 TanStack Query 的工作。
TanStack Router:型別安全的路由
一句話:管理「使用者在哪一頁」以及「網址列上的資訊」。
// 定義一個路由
const dashboardRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/dashboard',
component: DashboardPage,
})
// ↑ 當網址是 /dashboard 時,顯示 DashboardPage
Code language: JavaScript (javascript)它和傳統 React Router 最大的差別是 完全的 TypeScript 型別安全——路由參數、搜尋參數都有型別檢查,打錯字在編輯器裡就會被抓到。
TanStack Query:資料抓取與快取
一句話:管理「從 API 拿回來的資料」,包含快取、重新抓取、載入狀態。
// 抓取使用者資料
const { data, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
})
// ↑ queryKey 是快取的鑰匙,queryFn 是實際抓資料的函式
Code language: JavaScript (javascript)它幫你處理了這些你不想自己寫的東西:
- 載入中、成功、失敗三種狀態
- 自動快取(同樣的資料不重複抓)
- 背景重新抓取(使用者切回來時自動更新)
- 重試機制(網路斷了會自動重試)
核心概念翻譯
| 你會看到 | 意思 |
|---|---|
useQuery |
「從 API 讀取資料」的 hook |
useMutation |
「對 API 寫入/修改資料」的 hook |
queryKey |
快取的識別標籤,同樣的 key 共用同一份資料 |
queryFn |
實際去抓資料的函式 |
createRoute |
定義一個路由(網址對應哪個畫面) |
loader |
進入頁面前先抓資料的機制 |
技術棧架構圖:每一層負責什麼
這是你整個專案的分工圖:
┌─────────────────────────────────────────────┐
│ 使用者的瀏覽器 │
├─────────────────────────────────────────────┤
│ │
│ React(UI 層) │
│ 「畫面長什麼樣」 │
│ - Component 組合 │
│ - 事件處理(onClick 等) │
│ - 本地狀態(useState) │
│ │
├─────────────────────────────────────────────┤
│ │
│ TanStack Router(路由層) │
│ 「使用者在哪一頁」 │
│ - 網址 ↔ 畫面 的對應 │
│ - 路由參數(/users/123 的 123) │
│ - 搜尋參數(?page=2&sort=name) │
│ - 頁面切換的 loader(預先抓資料) │
│ │
├─────────────────────────────────────────────┤
│ │
│ TanStack Query(資料層) │
│ 「Server State 管理」 │
│ - API 資料的快取 │
│ - 載入 / 成功 / 失敗狀態 │
│ - 自動重新抓取與背景更新 │
│ - 樂觀更新(Optimistic Update) │
│ │
├─────────────────────────────────────────────┤
│ │
│ API / BaaS(後端服務) │
│ 「資料存在哪裡」 │
│ - Supabase / Firebase / 自建 API │
│ - REST 或 GraphQL │
│ │
└─────────────────────────────────────────────┘
每一層的職責翻譯
使用者點擊「訂單列表」
│
▼
TanStack Router:「網址要換成 /orders」
│
▼
TanStack Router 的 loader:「進入頁面前先抓訂單資料」
│
▼
TanStack Query:「快取裡有嗎?沒有就去 API 抓」
│
▼
API / Supabase:「這是訂單資料」
│
▼
TanStack Query:「存到快取,標記為成功」
│
▼
React:「資料來了,畫出訂單列表」
與其他方案的快速比較
React Router vs TanStack Router
| 比較項目 | React Router | TanStack Router |
|---|---|---|
| TypeScript 支援 | 有,但型別較鬆散 | 完全型別安全,路由參數自動推導 |
| 搜尋參數管理 | 手動解析 useSearchParams |
內建 JSON 搜尋參數、schema 驗證 |
| 資料預載 | v6.4+ 支援 loader | 原生 loader + 與 TanStack Query 深度整合 |
| 學習曲線 | 較低,文件多 | 較高,但型別提示能幫你少犯錯 |
| 適合場景 | 小型專案、快速原型 | 中大型 SPA、需要型別安全的團隊 |
SWR vs TanStack Query
| 比較項目 | SWR | TanStack Query |
|---|---|---|
| 核心理念 | 輕量、簡單 | 功能完整、企業級 |
| DevTools | 無官方工具 | 有官方 DevTools,可視化快取狀態 |
| Mutation 支援 | 基本 | 強大(樂觀更新、rollback) |
| 分頁/無限捲動 | 要自己實作 | 內建 useInfiniteQuery |
| Bundle 大小 | 較小 (~4KB) | 較大 (~13KB) |
| 適合場景 | 小型專案、簡單讀取 | 複雜的 CRUD 應用 |
如果你的專案有大量的 CRUD 操作(建立、讀取、更新、刪除),TanStack Query 的 mutation 和 DevTools 會幫你省很多時間。
最小範例:整體長什麼樣
讓我們看一個最精簡的範例,感受一下整個技術棧怎麼組在一起:
// main.tsx —— 應用程式入口
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { RouterProvider, createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen' // 自動產生的路由樹
const queryClient = new QueryClient() // 建立 Query 的快取管理器
const router = createRouter({ routeTree }) // 建立路由器
function App() {
return (
<QueryClientProvider client={queryClient}> {/* 提供快取管理器給整個應用 */}
<RouterProvider router={router} /> {/* 提供路由器給整個應用 */}
</QueryClientProvider>
)
}
Code language: JavaScript (javascript)逐行翻譯:
QueryClient— 建立一個「快取管理器」,所有 API 資料都存在這裡createRouter— 根據路由定義建立路由器QueryClientProvider— 讓所有 component 都能存取快取RouterProvider— 讓所有 component 都能做頁面切換
看到 AI 生成類似的代碼時,你只要知道:這是在設定應用程式的兩大基礎設施(路由 + 資料層)。
這套技術棧適合什麼專案?
非常適合
- Dashboard / 管理後台:登入後使用,不需要 SEO,大量的資料讀取與操作
- 內部工具:員工使用的管理系統、CRM、庫存管理
- SaaS 前台:登入後的應用介面,例如專案管理工具、分析平台
- 表單密集的應用:搭配 TanStack Form 可以處理複雜表單
不太適合
- 需要 SEO 的公開頁面:部落格、電商、行銷官網 — 考慮 Next.js 或 Astro
- 靜態內容為主:文件站、個人網站 — 考慮 Astro 或 VitePress
- 需要即時通訊:聊天室、協作工具 — 需要額外的 WebSocket 方案
本系列學習路線圖
你在這裡
↓
#01 架構總覽(本篇)
│ 瞭解「為什麼選這套」和「整體架構」
↓
#02 TanStack Router
│ 學會讀路由定義、參數、巢狀路由
↓
#03 TanStack Query
│ 學會讀 useQuery / useMutation、快取機制
↓
#04 Router + Query 整合
│ 學會讀 loader 模式、預取策略
↓
#05 實戰:Supabase CRUD
把所有東西串起來,做一個完整的應用
Code language: PHP (php)每一篇都會延續 Vibe Coder 的學習方式:重點不是教你從頭寫,而是讓你看懂 AI 生成的代碼在做什麼。
Vibe Coder 檢查點
看到 AI 幫你建了一個 React + TanStack 專案時,確認這些事:
- [ ] 有沒有搞清楚需不需要 SSR? 如果你的應用不需要 SEO,純前端 SPA 就夠了
- [ ] 架構分層對嗎? React 管 UI、Router 管頁面切換、Query 管 API 資料
- [ ] 有沒有不必要的框架? 如果 AI 建議 Next.js,但你做的是登入後的 Dashboard,考慮用純前端
- [ ] QueryClient 和 Router 有正確設定嗎? 入口檔案應該有
QueryClientProvider和RouterProvider - [ ] Query 的 key 有意義嗎?
queryKey應該能描述這筆資料是什麼(例如['users', userId])
必看懂 vs 知道就好
必看懂(本系列會一直出現)
| 概念 | 為什麼重要 |
|---|---|
useQuery / useMutation |
每個頁面都會用到的資料操作 |
queryKey / queryFn |
控制快取和資料來源的核心 |
createRoute / routeTree |
定義你的應用有哪些頁面 |
RouterProvider / QueryClientProvider |
應用程式入口的基本設定 |
loader |
進入頁面前預先載入資料 |
知道就好(遇到再查)
- Devtools:TanStack Query 和 Router 都有除錯工具,可以看快取狀態和路由狀態
- Optimistic Update(樂觀更新):先假設操作成功更新 UI,失敗再 rollback
- Infinite Query(無限捲動):處理「載入更多」的分頁模式
- Route Masking(路由遮罩):顯示的網址和實際路由不同
小結
這篇幫你建立了整體概念:
- 不是每個專案都需要 Next.js — Dashboard、內部工具、SaaS 前台用純前端 SPA 更簡單
- TanStack Router 管路由 — 型別安全的頁面切換和參數管理
- TanStack Query 管資料 — API 資料的快取、狀態管理、自動更新
- 四層架構:React(UI)→ Router(導航)→ Query(資料)→ API/BaaS(後端)
下一篇,我們會深入 TanStack Router,看懂路由定義、參數傳遞、和巢狀路由。
進階測驗:React + TanStack 架構總覽
共 5 題,包含情境題與錯誤診斷題。