5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue の状態管理ライブラリ Pinia を試してみる

Last updated at Posted at 2021-04-04

Vue で使える状態管理のライブラリ Pinia を試してみたのでメモです。
アイコンかわいい ! ドキュメントは コチラ

注意

この記事を書いている時点(2021/04/04) ではまだalpha版です!!

インストール

npm install pinia@next

Vue2 でも使えるみたいですがその場合は
pinia@latest@vue/composition-api をインストールすれば使えるようです。(試していません。)

app に Pinia を追加する

main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { createPinia } from "pinia";

createApp(App)
  .use(router)
  .use(createPinia()) //追加
  .mount("#app");

Store の定義

useUserStore.ts
import { defineStore } from "pinia";

export const useUserStore = defineStore({
  //idでストアを特定している。
  id: "user",

  //stateの定義、初期値を返す関数を定義する。
  state: () => ({
    firstName: "",
    familyName: "",
  }),

  getters: {
    fullName() {
      //thisでstateを参照できる。
      //補完も有効
      return `${this.firstName}${this.familyName}`;
    },

    hello() {
      //ゲッターも参照できる。
      return `Hello! ${this.fullName}`;
    },
  },
  actions: {
    setFullName(firstName: string, familyName: string) {
      this.firstName = firstName;
      this.familyName = familyName;
    },
    //Promiseを返すコードもかける
    async loadUser() {
      const user = await requestHoge..//サーバーにリクエストしデータを取得

      this.firstName = user.firstName;
      this.familyName = user.familyName;
    },
  },
});

こんな感じになります。

id でストアを紐づけて管理しているようです。

既存の値をもとに算出したい場合は gettersを使います。
thisを使うことで参照ができるようです。

コンポーネントから使う

QiitaSample.vue
<script lang="ts">
import { computed, defineComponent } from "vue";
import { useUserStore } from "./useUserStore";

export default defineComponent({
  name: "QiitaSample",
  setup() {
    const store = useUserStore();

    const firstName = computed(() => store.firstName);
    const familyName = computed(() => store.familyName);
    const fullName = computed(() => store.fullName);

    const setFullName = () => {
      store.setFullName("太郎", "キータ");
    };
    const loadUser = async () => {
      await store.loadUser();
    };
    return {
      firstName,
      familyName,
      fullName,
      setFullName,
      loadUser,
    };
  },
});
</script>

setup 関数の中で 先ほど定義したuseUserStore を呼び出すことで使えるようになります。

値を参照する

//stateから
const firstName = computed(() => store.firstName);
const familyName = computed(() => store.familyName);
//gettersから
const fullName = computed(() => store.fullName);

それぞれ computed を使うことでできます。

値を変更する

変更については様々な方法が用意されているようです。

直接代入

store.firstName = "太郎";
store.familyName = "キータ";

なんと、そのままストアに代入することもできます。

$patch を使う

store.$patch({
  firstName: "太郎",
  familyName: "キータ",
});

$patch を使う事でも状態を変更することができます。
state の変更したい部分だけ(例えばfirstName のみ) を渡すこともできます。

store.$patch((state) => {
  state.firstName = "太郎";
  state.familyName = "キータ";
});

このようにstate を引数とする関数を受け取ることもできます。

$state で全部置き換える

store.$state = {
  firstName: "太郎",
  familyName: "キータ",
};

$state に代入することで state 全体を置き換えることもできます。

action を実行する

const setFullName = () => {
  store.setFullName("太郎", "キータ");
};

そのまま呼び出すだけです。

const loadUser = async () => {
  await store.loadUser();
};

Promise を返すものは await を使うこともできます。

複数のストアを組み合わせる

useHogeStore.ts
import { defineStore } from "pinia";

export const useHogeStore = defineStore({
  id: "hoge",
  state: () => ({
    hogeName: "",
  }),
  getters: {
    enclosedHogeName() {
      return `[${this.hogeName}]`;
    },
  },
});
useFooStore.ts
import { defineStore } from "pinia";
import { useHogeStore } from "./useHogeStore";

export const useFooStore = defineStore({
  id: "foo",
  state: () => ({
    fooName: "",
  }),
  getters: {
    fooAndEnclosedHoge() {
      //ここでHogeStoreを参照する
      const hogeStore = useHogeStore();
      return `${this.fooName} ${hogeStore.enclosedHogeName}`;
    },
  },
});

getter の中で useXxxStore とすることで別のストアを参照できるそうです。

コードを見た感じ useXxxStore するたびに buildStoreToUse が呼ばれているように見えますがパフォーマンスはどうなんでしょね 🤔

別のストアを一つだけ参照するならこんな感じで良いみたいですけど
互いにいろいろ参照する場合は専用のストアを作ったほうが良いとのこと
(このあたり)

useSharedStore.ts
import { defineStore } from "pinia";
import { useFooStore } from "./useFooStore";
import { useHogeStore } from "./useHogeStore";

export const useSharedStore = defineStore({
  id: "shared",
  getters: {
    fooAndEnclosedHoge() {
      const hogeStore = useHogeStore();
      const fooStore = useFooStore();
      return `${fooStore.fooName} ${hogeStore.enclosedHogeName}`;
    },
  },
});

action も同様です。

まだドキュメントに書いていない機能

$reset

こちら

ストアを初期状態にする関数のようです

$subscribe

こちら

Vuexsubscribe みたいなものかな?

vuex-persisted-state のようにストレージに保存したりする用途に使えるかもしれない。

今のところ type に絵文字が入ってますね😅

さいごに

必要最小限の機能がそろっていて型もついているので便利そうな印象です。

正式リリースが楽しみですね

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?