🔍Vue 3 + Pinia 切換頁面回來卡頓?完整分析與解決方案

 

前言

在單頁應用(SPA)開發中,Vue 3 + Pinia 是非常常見的組合,可以有效管理全域與頁面狀態。
但是許多開發者在實作「切換頁面再回來時保留資料」時,常常遇到一個問題:頁面回來後卡卡的、甚至又重新撈一次資料

這篇文章將用一個實際案例,分析為什麼會卡頓、程式哪裡出了問題,以及如何修改程式碼讓切頁回來時瞬間顯示資料而不卡頓。




案例背景

假設我們有多個頁面(PageOne.vue、PageTwo.vue、PageThree.vue…),共同透過 Pinia 儲存:

  • 全域選取的版本 globalApsVersion

  • 每個頁面的表頭、表格資料、篩選條件

在 PageOne.vue 中,我們在 onMounted() 嘗試恢復儲存的資料:

const saved = store.pageStates[pageKey] || {}
if (saved.selectedVersion && saved.mappedTableData?.length) {
  selectedVersion.value = saved.selectedVersion
  tableHeaders.value = saved.tableHeaders
  mappedTableData.value = saved.mappedTableData
  filters.value = saved.filters
  initUniqueAndFilters()
  await nextTick()
  updateDummyScrollWidth()
  applySticky()
} else {
  await fetchPlanData()
}

看似沒問題,但實際上,這行

selectedVersion.value = saved.selectedVersion

會觸發:

watch(selectedVersion, fetchPlanData)

導致一進頁面時又重新呼叫 API 撈資料,造成卡頓與延遲。




問題原因

  1. selectedVersion 被改變 → 觸發 watch → 再次呼叫 API
    雖然我們只是想恢復資料,但實際上卻觸發了版本監聽器,重複查詢資料。

  2. watch 沒有防呆機制
    預設的 watch(selectedVersion, fetchPlanData) 在首次載入時就會觸發,不管你是不是只是從 Pinia 恢復資料。

  3. UI 沒有在 onActivated 重新套用 sticky 或 scroll 設定
    如果使用 <keep-alive>,切頁後回來 sticky 表頭可能失效,需要重新計算。




解決方案

1. 避免首次載入時觸發 API

不要在 onMounted() 中直接改 selectedVersion.value,改成:

if (saved?.selectedVersion && saved.mappedTableData?.length) {
  // 直接還原資料
  tableHeaders.value = saved.tableHeaders
  mappedTableData.value = saved.mappedTableData
  filters.value = saved.filters
  initUniqueAndFilters()
  await nextTick()
  updateDummyScrollWidth()
  applySticky()
} else if (selectedVersion.value) {
  await fetchPlanData()
}



2. 在 watch 加防呆

let firstLoad = true
watch(selectedVersion, async (newVal, oldVal) => {
  if (firstLoad) {
    firstLoad = false
    return
  }
  await fetchPlanData()
})

這樣首次載入時不會觸發 API,避免卡頓。




3. 在 onActivated 恢復 UI 狀態

onActivated(async () => {
  const saved = store.pageStates[pageKey]
  if (saved?.mappedTableData?.length) {
    tableHeaders.value = saved.tableHeaders
    mappedTableData.value = saved.mappedTableData
    filters.value = saved.filters
    initUniqueAndFilters()
    await nextTick()
    updateDummyScrollWidth()
    applySticky()
  }
})

確保切換回頁面時表格寬度、sticky 樣式都正確。




成果

修改後的效果:

  • 切頁回來時 瞬間顯示上次資料,不卡頓

  • 不會額外發送 API 請求

  • 表頭 sticky 與捲動條正常顯示




結語

這個案例告訴我們:

  • 狀態管理的恢復要小心觸發監聽器

  • watch 需要防呆機制

  • UI 狀態恢復要配合 onActivated 處理

這些細節不只是效能優化,更能提升使用者體驗。
如果你在 Vue 3 + Pinia 專案中遇到類似的問題,可以參考這套解法,保證切頁回來不卡頓。 🚀

留言

這個網誌中的熱門文章

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題

🛠【實戰排除教學】從 VS Code 的 _logger 錯誤,到 PowerShell 找不到 npm/serve,再到 Oracle ORA-03135 連線中斷——一次搞懂!

🔎如何在 Oracle PL/SQL 儲存過程中為文字欄位加入換行符號(CHR(10))——以 Updlcmremark 為例