Vue3のステート管理 Pinia まとめ

● 1. Piniaのデータ保存場所の作成

/stores/todos.ts を以下の内容で作成します。
これは次のような機能を持ったストアになります

・変数todos                 にTODOリストを保存
・todoOrderedDesc()     でID大きい順に並べ替えてリストを返す
・addTodo()                でリストの最後にメンバーを追加する
・changeName()         でidで指定したメンバの名前を変更する

記述方式はOptions APIライク(Vuexに似た昔ながらの書き方)でも、Composition APIライク(Vue3の書き方)でも
どちらでも記述することができます。 ここでは Composition API ライクで記述してみます。

stores/todos.ts

import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import _ from 'lodash'

interface Todo {
  id: number
  name: string
}

export const useTodoStore = defineStore('todo', () => {
  const todos = ref<Todo[]>([
    {
      id: 1,
      name: 'TODOその1'
    },
    {
      id: 2,
      name: 'TODOその2'
    }
  ])

  const todoOrderedDesc = computed(() => {
    return _.sortBy(todos.value, 'id').reverse()
  })

  function addTodo(newTodo: Todo) {
    todos.value.push(newTodo)
  }

  function changeName(id: number, name: string) {
    todos.value = todos.value.map((v) => {
      return v.id === id
        ? {
            id: id,
            name: name
          }
        : v
    })
  }

  return { todos, todoOrderedDesc, addTodo, changeName }
})

● 2. Piniaストアのデータの読み取り

import { storeToRefs } from 'pinia'
import { useTodoStore } from '../stores/todos'

const todoStore = useTodoStore()
const { todos } = storeToRefs(todoStore)

storeToRefs で todos を ref にすることでリアクティブに扱うことができます。

<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <div>{{ todo.id }} : {{ todo.name }}</div>
    </li>
  </ul>
</template>

● 3. Piniaストアの値の更新

/stores/todos.ts に定義した更新メソッドを呼び出して値を更新します

  todoStore.changeName(1, 'TODOその1 ● 変更')

(注意)直接値を更新することもできてしまいます https://github.com/vuejs/pinia/issues/58

  todos.value = []

● 4. Piniaストア値のreadonly

1. 完全な readonly

const { todos } = storeToRefs(todoStore)

  ↓ 次のように修正して readonly にします

const { todos: todosMutable } = storeToRefs(todoStore)
const todos = readonly(todosMutable)

これでこのコンポーネント内では「値の変更やデータの追加、削除などができない事が担保された状態」で扱うことができます。
/stores/todos.ts で定義した更新メソッドもこのコンポーネント内では実行することができなくなります

2. Piniaストア値をコンポーネントで直接編集させないようにする readonly

/stores/todos.ts を以下のように修正します

  return { todos, todoOrderedDesc, addTodo, changeName }

  ↓

  return { todos: readonly(todos), todoOrderedDesc, addTodo, changeName }

これで

// これは以下のエラーによって実行できなくなります
//  [Vue warn] Set operation on key "value" failed: target is readonly.

  todos.value = []

この方法だと更新メソッドは問題なく使用することができます。

No.2248
12/14 23:52

edit