iT邦幫忙

2025 iThome 鐵人賽

DAY 24
1
Vue.js

在 Vue 過氣前要學的三十件事系列 第 24

在 Vue 過氣前要學的第二十四件事 - 蟹老闆你有感覺了嗎 / 跨頁表單驗證 ( 上 ) / Pinia

  • 分享至 

  • xImage
  •  

前言

在此篇章中我們將會帶到如何使用狀態管理工具 + 驗證工具 來實現跨頁表單驗證的功能
讓各位在實作中了解何為狀態管理,驗證的時機,以及還有什麼工具可以做延伸閱讀

何為狀態管理

雖然說我們前面在響應式系統篇章有帶到 狀態 State,但只是粗淺帶過
這邊會再深入講解,

定義

The state, the source of truth that drives our app.
狀態:驅動整個應用的數據源

https://ithelp.ithome.com.tw/upload/images/20250924/20172784if3CqB9QUo.png

我們知道 Vue 是一個資料驅動的框架,

根據上面的圖片我們可以知道紫色的 State( 狀態 )
將會使 View ( 畫面 ) 更新,
而用戶在畫面上的 Actions ( 操作 ) 又會使狀態變更

這樣一個簡單的資料流在單個組件中,是非常好理解的,
我再用一個圖解例子讓大家能更好的理解狀態管理:

  • View 就是你畫面上的東西,只 for 顯示。
  • State 是一種數據狀態,可能是開關,也可能是文字。
  • Actions 是用戶的動作,例如點擊。

那這邊的流程就是:

  1. 初始狀態( State ) 關閉 → 盒子( View )關著
  2. 按鈕 ( View ) → 用戶按下 ( Actions ) → 按下更改狀態為開 ( State )
  3. 狀態( State ) 為開 → 驅動盒子畫面為開著的樣子 ( View )

那麼在單一組件自行管理狀態的情況下是非常好懂的
但如果今天是需要讓多個畫面都依賴於同一個狀態,那就稍微有點複雜了,

如果都依賴 props 和 emit,先不考慮程式碼會變得雜亂,
要是這些共享同一狀態的組件不存在父子關係,那就會變得很麻煩。

在進入我們今天的主角 Pinia 之前,
先來用響應式 API 來簡單做一個狀態管理。

簡易狀態管理實作


資料夾架構為下 :

├─ App.vue
│  ├─ CompA.vue
│  └─ CompB.vue
│
└─ store.js
<!-- App.vue -->
<script setup>
import { store } from './store';
import CompA from './CompA.vue';
import CompB from './CompB.vue';
</script>

<template>
  <CompA/>
  <CompB/>
  <button @click="store.increment">按我+1</button>
</template>
<!-- CompA.vue -->
<script setup>
import { store } from '../store';
</script>

<template>
  <p>From A: {{ store.count }}</p>
</template>
<!-- CompB.vue -->
<script setup>
import { store } from '../store';
</script>

<template>
  <p>From A: {{ store.count }}</p>
</template>
import { ref } from 'vue'

export const store = ref({
  count: 0,
  increment() {
    this.count++
  }
})

當我們點擊在 App.vue 的按鈕時,
可以不透過 props 傳遞,而是一次更改全局狀態;

來驅動 CompA 跟 CompB 更改數據,這就是一個很簡單的全局狀態管理,
但聰明的你已經發現了,這樣做的狀態管理是有一定的危險性的。

因為不管哪個組件都有可能更改到其他地方的數據,因此在考慮使用狀態管理時要十分小心。

這邊有 遊樂場 給大家玩一下

那下面我們就正式進入今天的主角 Pinia

安裝 Pinia

$ npm install pinia
// main.js
import { createSSRApp } from 'vue';
import { createPinia } from 'pinia';

const app = createApp(App);
const pinia = createPinia();

app.use(pinia).mount("#app");
//記得安裝完要全局註冊

題外話

https://ithelp.ithome.com.tw/upload/images/20250924/2017278450clXVGQ7E.png
Pinia 在西班牙語裡面是鳳梨的意思,而鳳梨花其實是一組各自獨立的花朵,

當它們最終結合時形成一個多重組合的水果,
跟 Store 的確有異曲同工之妙,非常有趣。

使用

//stores/counter.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter',{
  state(){},// 存放狀態,似 ref
  getters:{},// 對狀態做一些處理,似 computed
  actions:{}, // 讓你定義一些方法,似 function
})

實際寫起來可能會是這樣 :

//stores/counter.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter',{
  state(){
      return{
          count:0
      }
  },
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
<script setup>
import { useCounterStore } from '@/stores/counter'
import { computed } from 'vue'
import { storeToRefs } from 'pinia'

const store = useCounterStore()

//❌以下這行是錯誤示範,請"不要"用這種方式解構,會失去響應式
//const { name, doubleCount } = store
//✅真的要解構你可以使用 storeToRefs()
// 這邊記得實際開一個專案測試會不會報錯或有其他情況
const { name, doubleCount } = storeToRefs(store)

function increment(){
  store.increment();
}

const doubleValue = computed(() => store.doubleCount);
</script>

如果不管你是一直寫 Vue3( CompositionAPI ),
還是有寫過 Vue2( OptionAPI ) 的人,都應該會對這個寫法有點想法,

沒錯 上面這個寫法接近 OptionAPI 的寫法,這種寫法稱為 Option Store,
那其實還有接近 Vue3 的 Setup Store,類似於 CompositionAPI,

//Setup Store
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)// 等同 state
  const doubleCount = computed(() => count.value * 2)//等同 getters
  function increment() { //等同 actions
    count.value++
  }

  return { count, doubleCount, increment } //最後將返回值暴露給呼叫 store 的組件
})

在使用上 Setup Store 或 Option Store 沒有孰優孰劣
並不是說你寫 Vue3 就要用 Setup Store,寫 Vue2 就要寫 Option Store
選擇自己最舒服的寫法和團隊規定的就好。

結語

今天我們從何為狀態 ( State ) 開頭,
一步一步了解 Vue 的狀態管理流程;

試著不依靠工具手寫簡易狀態管理,再踏入 Pinia 的大門;

說明的 Pinia 的兩種基本寫法,請根據自己的習慣方法或團隊規定來做即可;
https://ithelp.ithome.com.tw/upload/images/20250924/20172784COrUNRiYQ1.png
那明天我們將進入驗證工具環節,敬請期待~

一些小練習

  1. state, getters, actions 在 Setup Store ( Composition API ) 中等同於什麼 ?
  2. 使用全局狀態管理時,跟單純依賴單向資料流(props + emits)相比,會容易遇到什麼問題?
  3. Option Store 跟 Setup Store 各自有什麼優缺點 ?


上一篇
在 Vue 過氣前要學的第二十三件事 - 小孩才做選擇 ( 下 ) / CSS Variable & Design Token
系列文
在 Vue 過氣前要學的三十件事24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言