iT邦幫忙

2022 iThome 鐵人賽

DAY 17
1
自我挑戰組

程式小白的 vue.js 學習筆記系列 第 17

Day 17 : 【 Vue 的狀態管理工具 2】 pinia

  • 分享至 

  • xImage
  •  

首先,可以先講一下我們為何需要狀態管理。

當我們在進行一個專案時,常常需要資料在元件或頁面間互通有無,我們可能會使用props、emit,或者 provide、inject,又或者直接用 mitt 套件來傳 XD

如果是小專案的話那還好,專案架構一大、你 mitt 來 mitt 去的東西越來越多、越來越亂,更不要說 mitt 很難除錯了XDD

這時候我們就可以透過狀態管理工具,將 store 中的資料分成各類的state 集中管理,當一處的資料改動,其他頁面的資料也會同時更動拉 ~

以往 Vue 所使用的狀態管理工具通常為 Vuex,這次所學習的 pinia 算是 Vuex 的後繼者,詳情可見 這篇介紹文 ~


今天來記錄的是,如何在 vue 的環境中引入 pinia。

首先,當然是先 install 下來XD

npm install pinia

引入 pinia

接著來到 你的 main.js

import { createApp } from 'vue'
// 匯入 createPinia 方法
import { createPinia } from 'pinia' // here

// 進行初始化
const pinia = createPinia() // here
const app = createApp(App)

app.use(pinia) // here
app.use(router)

app.mount('#app')

新增一個 stores 檔案夾 管理資料狀態

建立一個叫做 stores 的資料夾,然後在裡面開一個 user.js

// 匯入 defineStore 的方法
import { defineStore } from 'pinia'

// 這裡帶入兩個參數,一個是store 名稱、另一個是屬性參數
export default defineStore('userStore', {
  // 對應 data
  state: () => ({
    name: 'Jenny',
    wallet: '300'
  }),

  // 對應 computed (物件形式)
  getters: {
    getUserName: (state) => `我的名字叫${state.name}`
  },

  // 對應 methods (物件形式)
  actions: {
    updateName () {
      this.name = 'Angel'
    }
  }
})

options API 寫法

接著找一個頁面,分別在 methods, computed 中展開 mapState 和 mapActions,並帶入兩個參數。

{{name}} {{getUserName}}
<button type="button" @click="updateName">按我</button>
<script>
// 匯入 mapState、 mapActions 方法
import { mapState, mapActions } from 'pinia'
// 匯入 你剛剛建立好的store
import userStore from '@/stores/user'
export default {
    methods:{
        // 這裡帶入兩個參數 : 一個是Store,另一個是要帶入的actions
    ...mapActions(userStore, ['updateName']),
    },
    computed: {
    // 這裡帶入兩個參數 : 一個是Store,另一個是要帶入的state,getters
    ...mapState(userStore, ['name', 'getUserName'])
  },
}
</script>

composition API 寫法

基本上,我們在 store 所定義的資料,都是 reactive 的

{{user.name}} {{user.wallet}}
{{name}} {{wallet}}
<button type="button" @click="updateName">按我</button>
<button type="button" @click="updateData">updateData</button>
<button type="button" @click="reset">reset</button>

<script>
// 匯入 你剛剛建立好的store
import userStore from '@/stores/user'
import { storeToRefs } from "pinia"
export default {
    setup(){
        const user = userStore()
        
        // 也可以直接修改從 store 來的資料
        // user.name = "Lia"
        
        // 也可以直接把值從 store 給取出來與修改
        const { name,wallet,getUserName } = storeToRefs(user);
        name.value = "Lia"
        
        // 如果不須雙向綁定(如方法),可以從 user 取
        const { updateName } = user
        
        function updateData(){
            // 這是另一種修改來自 store 值的方法
            user.$patch({
                name:"Lia",
                wallet:1000
            })
        }
        
        function reset(){
            // 我們可以透過 $reset 來重置資料內容。
            user.$reset();
        }
    }
    return {
        user,
        name,
        wallet,
        getUserName,
        updateName
    }
}
</script>

最後渲染畫面看看有沒有吃到資料~

同時,我們也可以打開開發者工具來看看 :

如何在 store 中 引用另一個 store?

這裡的 status 主要是放一些過渡小動畫。

假如要在 store 裡面引用,如以下用法 :

// 匯入 defineStore 的方法
import { defineStore } from 'pinia'

import statusStore from './statusStore'// 新增
const status = statusStore() // 新增

// 這裡帶入兩個參數,一個是store 名稱、另一個是屬性參數
export default defineStore('userStore', {
  // 對應 data
  state: () => ({
    name: 'Jenny',
    wallet: '300'
  }),

  // 對應 computed (物件形式)
  getters: {
    getUserName: (state) => `我的名字叫${state.name}`
  },

  // 對應 methods (物件形式)
  actions: {
    updateName () {
      this.name = 'Angel'
      status.isBounced = true // 取用statusStore的 state(data) (新增)
    }
  }
})

更新提醒

在使用 pinia 後使用路由跳轉時,會出現以下錯誤。

Uncaught ReferenceError: Cannot access 'useAuthStore' before initialization
at axiosroot.ts

根據這篇的解釋,我們需要更改一下 main.js的設定

import { createApp, markRaw } from 'vue'
// 匯入 createPinia 方法
import { createPinia } from 'pinia' // here

// 進行初始化
const pinia = createPinia() // here
const app = createApp(App)

app.use(pinia) // here
// 在每個store 添加 pinia
pinia.use(({ store }) => {
  store.$router = markRaw(router)
})
app.use(router)

app.mount('#app')

上一篇
Day 16 : 【 Vue 的狀態管理工具 1】 Vuex
下一篇
Day 18 : 【Vue Router 1】Vue Router 簡介
系列文
程式小白的 vue.js 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chiayinin
iT邦新手 4 級 ‧ 2023-02-14 12:02:39

寫得很清楚!謝謝教學。
另外想問,有看過有人在 options API 寫 setup() 來引入 store,這個用法跟 data() 雷同,實務上是可以這樣寫的嗎?

我要留言

立即登入留言