はじめに
-
プロジェクトでVuexをPiniaへ移行する作業を行ったのでその作業手順メモ。
-
store数が多かったので、VuexとPiniaを並行導入しつつ、段階的にPiniaへ移行した。
-
基本的にはマイグレーションガイドを見れば問題なかった。
移行手順の記録
piniaのインストール
yarn add pinia
main.tsの設定
-
createPinia()
を追加する。並行稼働するため、Vuexのstore設定も残す - VuexはDynamicImportをするために、store/index.tsで空storeを作成してる
- PiniaではDynamicImportの設定は不要(必要な時に作られる)なので、storeの初期化不要。
main.ts
import store from '@/store' // Vuexのstore初期化ファイル。
+ import { createPinia } from 'pinia'
...
app.use(store)
+ app.use(createPinia())
...
storesフォルダにstoreファイルを作成
- Vuexはstoreフォルダ(sなし)で別で管理できるので、並行稼動ができる。
- setup構文が使えるので、stateはref関数、getterはcomputed、actionは関数で定義できる。
- ※なお、mutationは存在せず、actionに含める。
- 名称はuseXXXとし、composition-apiとして配布する。
- 以下、before, after例。なお、beforeは
vuex-module-decorators
記法で記載。通常のVuex記法はマイグレーションガイドに記載されているので、そちらを参照。- ※vuex-module-decorators:クラス構文と専用のデコレータでvuexの定義が行える。クラスの恩恵が受けれるため、型定義などがしやすい。が、関数型プログラミンが主流となったことで利用されなくなった。(現在メンテされていない)
before(vuex-module-decorators記法)
import { VuexModule, Module, Action, Mutation, getModule } from 'vuex-module-decorators'
import store from '@/store'
export interface ICompany {
id: string
name: string
}
// DynamicImportの設定
@Module({ dynamic: true, store, name: 'company' })
class Company extends VuexModule implements ICompany {
// stateはフィールド
public id = ''
public name = ''
// getter
get comanyIdName() {
return `${this.id}:${this.name}`
}
@Mutation
private SET_COMPANY(company: ICompany) {
this.id = company.id
this.name = company.name
}
// アノテーションで設定する
@Action
public setCompany(company: ICompany) {
this.SET_COMPANY(company)
}
}
export const CompanyModule = getModule(Company)
after(Pinia-setup記法)
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
export interface ICompany {
id: string
name: string
}
export const useCompanyStore = defineStore('company', () => {
// stateはref変数
const id = ref('')
const name = ref('')
// gettterはcomputed
const companyIdName =computed(()=> `${id.value}:${name.value}`)
// actionはmutationと統合して、関数
const setCompany = (company: ICompany) => {
id.value = company.id
name.value = company.name
}
return { id, name, companyIdName, setCompany }
})
- ちなみに、returnするものが多い場合は、定義時に関数化してまとめるとよい。
export const useUserStore = defineStore('XXX', () => {
const useUserState = () => {
return {
name: ref(''),
email: ref(''),
...
}
}
const userState = useUserState()
const useComputables = () => {
return {
isUser: computed(() => XXXX),
isCompany: computed(() => XXXX),
...
}
}
const computables = useComputables()
return { ...userState, ...computables }
利用側の修正
- 作成したuse関数を使用し、利用箇所を置き換えるだけ。
- import { CompanyModule } from '@/store/modules/company'
+ import { useCompanyStore } from '@/stores/company'
// use関数を使用する。(変数名も同じ(CompanyModule)にすれば実質変更はここだけ。)
+ const companyStore = useCompanyStore()
...
- CompanyModule.setCompany({
+ companyStore.setCompany({
name: item.name,
id: item.id
})
- const id = companyModule.id
+ const id = companyStore.id
- tsファイルの場合、topレベルで呼び出すと
undefinde
になってしまうので、関数内で取得する- ここで、はまってしまった。がよく考えれば、
script setup
もdefineComponent
関数のシンタックスシュガーだったから、関数内で取得しているのか。 - 公式の移行手順に思いっきり書かれてた。。。
- ここで、はまってしまった。がよく考えれば、
Vuexの削除
- すべての動作確認が終わり、移行が問題なければ、Vuexの資材を削除する。
-
store
フォルダの削除 - main.tsの設定削除
-
main.ts
- import store from '@/store' // Vuexのstore初期化ファイル。
...
- app.use(store)
...
- 最後に、Vuexをアインストールして作業完了
- package.jsonフォルダ直下で以下を実行
yarn remove vuex
yarn remove vuex-module-decorators
- 念のためキャッシュクリア、node_module入れ替えを行い(以下)、動作を再度確認した。
rm -rf node_modules
yarn cache clean
yarn install
おわりに
- 移行は、他のVu3系ライブラリに比べて格段に簡単だった。
- mutationがなくなったこと、setup構文で記載できることで、非常に簡潔にかけるようになった。
- Vuexで問題視されていた、複雑な型定義も解消されたので、Pinia移行は非常におすすめ。
- ※複雑な型定義問題で、
vuex-module-decorators
を使用する経緯となっった。
- ※複雑な型定義問題で、