Introduce to Pinia🍍
v-kansai Vue.js/Nuxt Meetup #13【v-Shinnenkai】
chan_kaku
chan_kakuz
chan_kaku
takumiz19
Who?
FURYU Corp. @Kyoto
ServerSide Engineer
- Java
- Kotlin
Spring/Vue.js/Architecture/Test
角田拓己
Piniaのお話
#1
Piniaとは?
Composition APIを利用してStoreがどうあるべきか
追求するためのプロジェクト
元々はスペイン語のPiña(パイナップル)からきているがパッケージ名にスペイン語を使えなかったため一番近い発音のものに
そもそもComposition API
とは?
#2
来たるVue 3.0で追加される
目玉のAPI
ちなみに現状でもComposition APIを利用することができます!
機能を要素ごとにまとめることができる
良いところ
-
this地獄がなくなる
-
よりviewとロジックを分離させやすくなった
this地獄がなくなる
<template>
<button @click="increment">
Count is: {{ state.count }}, double is: {{ state.double }}
</button>
</template>
<script>
import { reactive, computed } from 'vue'
export default {
setup() {
const state = reactive({
count: 0,
double: computed(() => state.count * 2)
})
function increment() {
state.count++
}
return {
state,
increment
}
}
}
</script>
よりviewとロジックを
分離させやすくなった
function useCreateFolder (openFolder) {
// originally data properties
const showNewFolder = ref(false)
const newFolderName = ref('')
// originally computed property
const newFolderValid = computed(() => isValidMultiName(newFolderName.value))
// originally a method
async function createFolder () {
if (!newFolderValid.value) return
const result = await mutate({
mutation: FOLDER_CREATE,
variables: {
name: newFolderName.value
}
})
openFolder(result.data.folderCreate.path)
newFolderName.value = ''
showNewFolder.value = false
}
return {
showNewFolder,
newFolderName,
newFolderValid,
createFolder
}
}
mixinでもできたけど、、、、
微妙なところ
自由度が高くなったことで規約をちゃんと作らないともとよりすごいスパゲッティコードが出来上がる
注意
Piniaの特徴
#3
-
Vuexより軽量
-
基本的にはstateとgettersだけ
-
SSRサポート
-
DevToolsサポート
SSRサポート
export function createApp() {
// Here there could also be a router
const store = useStore(true)
// we can change the state now!
store.state.counter++
// create the app instance
const app = new Vue({
render: h => h(App),
})
// expose the app and the store.
return { app, store }
}
基本的にはVuexと同じ書き方でSSRも対応できる
DevToolsサポート
実際に使ってみる
#4
Storeの実装
import { createStore } from 'pinia'
export const useMainStore = createStore(
// name of the store
// it is used in devtools and allows restoring state
'main',
// a function that returns a fresh state
() => ({
counter: 0,
name: 'Eduardo',
}),
// optional getters
{
doubleCount: state => state.counter * 2,
}
)
Storeを利用
import { useMainStore } from '@/stores/main'
export default createComponent({
setup() {
const main = useMainStore()
return {
// gives access to the whole store
main,
// gives access to the state
state: main.state,
// gives access to specific getter,
}
},
})
MutationとActionは?
まずはMutation
//単純に
main.state.counter++
//もしくは複数を一気に変更したい場合
main.patch({
counter: 3,
name:'hoge'
})
続いてAction
export async function login(user, password) {
const store = useUserStore()
const userData = await apiLogin(user, password)
store.patch({
name: user,
...userData,
})
}
ただのビジネスロジックを含んだ関数
Piniaを使った応用
#5
Shared Getters
import { computed } from '@vue/composition-api'
import { useUserStore } from './user'
import { useCartStore } from './cart'
export const summary = computed(() => {
const user = useUserStore()
const cart = useCartStore()
return `Hi ${user.state.name}, you have ${cart.state.list.length} items in your cart. It costs ${cart.price}.`
})
Shared Actions
import { useUserStore } from './user'
import { useCartStore, emptyCart } from './cart'
export async function orderCart() {
const user = useUserStore()
const cart = useCartStore()
try {
await apiOrderCart(user.state.token, cart.state.items)
emptyCart()
} catch (err) {
displayError(err)
}
}
でっかいStoreではなくある構成ごとに切り出すことができる
ユニットテストがやりやすく
Creating Pinias
import { pinia } from 'pinia'
import { useUserStore } from './user'
import { useCartStore, emptyCart } from './cart'
export const useCartUserStore = pinia(
{
user: useUserStore,
cart: useCartStore,
},
{
combinedGetter: state =>
`Hi ${user.state.name}, you have ${cart.state.list.length} items in your cart. It costs ${cart.price}.`,
}
)
export async function orderCart() {
const store = useCartUserStore()
try {
await apiOrderCart(store.state.user.token, store.state.cart.items)
emptyCart()
} catch (err) {
displayError(err)
}
}
まだ実装されてません
注意
まとめ
-
Vuex以外の状態管理の手段を紹介
-
まだ実験的なプロジェクトなので、本番運用は推奨されていない
-
Vue 3.0が出てきてからいろんなStoreのあり方を考えて行くのも面白いかも