Lala Code

Lala 的前端大補帖,歡迎一起鑽研前端技術😊

0%

Pinia 的全域資料管理

Pinia
在 Vue2 時我們常常使用 Vuex 來做共用邏輯,組件之間的溝通,在 Vue 升級後,Vue3 官方有意將 Vuex 換成 Pinia

Pinia 相對來說沒有太多複雜的邏輯,你可以把它當成是沒有 mutations 的 Vuex,當然,在 Vue3 還是可以使用 Vuex 來操作,但 Pinia 的出現,你可以省去很多學習成本,又可以直接在 store 裡使用 composition API。

事不宜遲,來使用看看吧!



安裝 Pinia

選擇自己喜歡的方式安裝

NPM

1
npm install pinia

YARN

1
yarn add pinia


引入 Pinia

main.js

1
2
3
4
5
6
7
8
9
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

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

app.use(pinia);
app.mount('#app');

引入後就可以來操作 Pinia 囉!



建立 stores 檔案

在 src 底下建立 stores 資料夾,裡面可以依專案需求來放置檔案

範例先使用 counter.js

1
2
3
4
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
// more...
})
  • defineStore 第一個參數為 id,給 pinia 做 store 和 devtools 的連接
  • 會以 use 來做變數開頭命名

Pinia 可以用操作起來像 Vuex 一樣的 Option Store,也可以使用 Setup Store,兩種操作起來不太一樣,以下為兩者介紹



Option Store

stores/counter.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
state: () => {
return { counter: 0 }
},
getters: {
doubleCount: (state) => state.counter * 2
},
actions: {
addCount() {
this.counter++
},
},
})
  • Pinia 沒有 Vuex 的 mutations
  • actions 要用 this 指向 state

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import { useCounterStore } from "./stores/counter";
const store = useCounterStore();
const clickAdd = () => {
store.addCount();
}
</script>

<template>
<h1>{{store.counter}}</h1>
<button type="button" @click="clickAdd">
add
</button>
</template>
  • Pinia 取出 stores 值時,不需要再寫 state、dispatch、getters,可以直接取得值

Setup Store

使用 Composition API 可以像 Vue3 使用 Component 的方式,使用 ref、reactive、computed 等等,並將要用的資料 return 出去給外面的檔案使用

stores/counter.js

1
2
3
4
5
6
7
8
9
10
11
12
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export const useCounterStore = defineStore('counter', () => {
const counter = ref(0);
const doubleCount = computed(() => counter.value * 2)
function addCount() {
counter.value++
}

return { counter, doubleCount, addCount }
})
  • 第二個參數為 function,裡面直接可以使用 Composition API

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import { useCounterStore } from "./stores/counter";
const store = useCounterStore();
const clickAdd = () => {
store.addCount();
}
</script>

<template>
<h1>{{store.counter}}</h1>
<button type="button" @click="clickAdd">
add
</button>
</template>

如此一來會跟 Options API 寫法的結果是一模一樣的,且無需處理 this 指向,與使用 Components 的 codeing style 也是一致的,寫法也更清楚簡潔



Setup Store 取 API

Setup Store 取 API 也是非常簡單,用 axios 取得 API 資料後,再從外部取得

stores/counter.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { defineStore } from 'pinia';
import { ref } from 'vue';
import axios from "axios";

export const useCounterStore = defineStore('counter', () => {
const name = ref('');

const fetchName = async() => {
try {
const res = await axios.get('https://randomuser.me/api/');
name.value = res.data.results[0].name;
} catch (error) {
console.log(error);
}
}

return { name, fetchName }
})

App.vue

1
2
3
4
5
6
7
8
9
10
11
<script setup>
import { useCounterStore } from "./stores/counter";
const store = useCounterStore();
</script>

<template>
<h1>{{ store.name.first }} {{ store.name.last }}</h1>
<button type="button" @click="store.fetchName">
fetchName
</button>
</template>


Pinia 解構,storeToRefs 包裝資料

上面的範例,會看到很多都是 store 出來的,這時可以使用解構,讓程式碼簡潔一點,不過要注意的是,因 store 是用 reactive 包裝的對象,資料如果從 store 解構出來,將會破壞響應性,所以~

Pinia 的 function 可以直接從 store 解構出來,但純資料解構需使用 storeToRefs 包裝起來

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script setup>
import { storeToRefs } from "pinia";
import { useCounterStore } from "./stores/counter";
const store = useCounterStore();
const { addCount, fetchName } = store;
const { name, counter } = storeToRefs(store);
</script>

<template>
<h1>{{counter}}</h1>
<button type="button" @click="addCount">
add
</button>

<h1>{{ name.first }} {{ name.last }}</h1>
<button type="button" @click="fetchName">
fetchName
</button>
</template>


Store 之間的傳遞

store 之間有可能也會傳遞資料,import store 直接就可以使用,如以下範例,我們傳遞了 aboutStore 的 user 給 counterStore 做使用

store/about.js

1
2
3
4
5
6
7
8
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useAboutStore = defineStore('about', () => {
const user = ref('Lala');

return { user }
})

stores/counter.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { defineStore, storeToRefs } from 'pinia';
import { ref, computed } from 'vue';
import axios from "axios";
import { useAboutStore } from "./about";

export const useCounterStore = defineStore('counter', () => {
const aboutStore = useAboutStore();
const { user } = storeToRefs(aboutStore);

const counter = ref(0);
const doubleCount = computed(() => counter.value * 2 + user.value)
function addCount() {
counter.value++
}

const name = ref('');

const fetchName = async() => {
try {
const res = await axios.get('https://randomuser.me/api/');
name.value = res.data.results[0].name;
} catch (error) {
console.log(error);
}
}

return { counter, doubleCount, addCount, name, fetchName }
})


REFERENCE

Vue3 + Vite 快速上手 Get Startrd EP6 - Pinia 的全域資料管理!
Pinia 官方



Hey!想學習更多前端知識嗎?

最近 Lala 開了前端課程 👉【實地掌握RWD - 12小時新手實戰班】👈
無論您是 0 基礎新手,又或是想學 RWD 的初學者,
我們將帶你從零開始,深入了解並掌握 RWD 響應式網頁設計的核心技術,快來一起看看吧 😊



🚀線上課程分享

線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程
想學習更多關於前後端的線上課程,可以參考看看。

Hahow

Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住



六角學院

如果你是初學者,非常推薦六角學院哦!
剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!


Udemy

Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!
也是很多工程師推薦的線上課程網站。
❤️