在 Vue 裡面使用 pinia 管理狀態
pinia 是 Vue 官方推薦的狀態管理工具,可以解決跨元件之間資料傳遞要反覆的 props 及 emit 的問題,只要把資料跟方法放在 store 裡面,就可以讓所有的元件取用,不但傳遞變簡單了,在管理資料上面也變得更清楚。
首先安裝 pinia
npm install pinia
main.js 中初始化
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia";
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.mount("#app");
在 src 下面建立 stores 資料夾,然後在 stores 裡面建立 user.js。
import { defineStore } from "pinia";
// userStore 為自定義名稱
// {屬性參數}
export default defineStore("userStore", {
// data
state: () => ({ name: "鋼鐵人", friend: "蜘蛛人" }),
// computed
getters: {
getUserName(state) {
return `${state.name} 和 ${state.friend}是好朋友`;
}
},
// methods
actions: {
// 可以使用 this,所以不用箭頭函式
updateFriend() {
this.friend = "美國隊長";
}
}
});
HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>{{ name }},{{ friend }}</h2>
<h2>{{ getUserName }}</h2>
<button type="button" @click="updateFriend">更新復仇者好友</button>
</div>
</template>
<script>
import { mapState, mapActions } from "pinia";
import userStore from "@/stores/user";
export default {
name: "HelloWorld",
props: {
msg: String,
},
computed: {
...mapState(userStore, ["name", "friend", "getUserName"]),
},
methods: {
...mapActions(userStore, ["updateFriend"]),
},
};
</script>
在 Composition 中使用 pinia
簡單初始化,首先
import userStore from "@/stores/user";
使用 reactive 格式
然後在 setup()
把 userStore
賦值給一個常數 user
,記得要 把 user
給 return
出去。
然後在 HTML 中使用 {{ user.變數名稱或方法 }}
, 就可以綁定 user.js
裡面 state
定義的資料、 getters
及 actions
中的方法,而且這樣的情形下,資料及方法都是 reactive
格式的,所以可以做到雙向綁定。
HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>{{ user.name }},{{ user.friend }}</h2>
<h2>{{ user.getFriendName }}</h2>
<button type="button" @click="user.updateFriend">更新復仇者好友</button>
</div>
</template>
<script>
import userStore from "@/stores/user";
export default {
name: "HelloWorld",
props: {
msg: String,
},
setup() {
const user = userStore();
//state 中的資料為 reactive 格式
return {
user,
};
},
};
</script>
使用 ref 格式
要使用 ref
格式,除了 import userStore from "@/stores/user";
之外,還必須匯入一個 pinia
提供的 { storeToRefs }
方法,把 store
中定義的方法跟資料轉為 ref
格式:
import { storeToRefs } from "pinia";
然後在 setup() 中,取出 store 中的變數及方法:
const { name, friend, getFriendName } = storeToRefs(user);
// 如果要改變 變數的值,記得加上 .value
name.value = '雷神'
return
的時候除了 user
之外, name
、 friend
及 getFriendName
也要記得 return
出去。
這時 HTML 中的 {{ user.xxxx }}
就可以拿掉了。但是如果要在 setup()
中更改 變數的值,就要像使用 ref
一樣,加上 xxxx.value
。
如果在 state 中不用作到雙向綁定的,就直接取出
// 不用雙向綁定 直接取出
const { updateFriend } = user;
HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>{{ user.name }},{{ user.friend }}</h2>
<h2>{{ user.getFriendName }}</h2>
<!-- user 可以拿掉 -->
<h2>{{ name }},{{ friend }}</h2>
<h2>{{ getFriendName }}</h2>
<!-- 雙向綁定也可以 -->
<input type="text" v-model="user.name" />
<button type="button" @click="user.updateFriend">更新復仇者好友</button>
</div>
</template>
<script>
import { storeToRefs } from "pinia";
import userStore from "@/stores/user";
export default {
name: "HelloWorld",
props: {
msg: String,
},
setup() {
const user = userStore();
// 轉成 ref 格式
const { name, friend, getFriendName } = storeToRefs(user);
// ref 格式,state 中的變數須加上 .value
name.value = "雷神";
// 不用雙向綁定 直接取出
const { updateFriend } = user;
return {
user,
name,
friend,
getFriendName,
};
},
};
</script>
使用 pinia 提供的 patch 方法修改資料:
function updateData() {
user.$patch({
name: "浩克",
friend: "薩諾斯",
});
}
使用 pinia 提供的 reset 方法重置資料:
function reset() {
user.$reset();
}