目次
Vue 基本構造
- 基本構造説明 - Composition API 方式( 別の方式ではOption API方式がある export default{} )
<script setup>
// storeを import
import { useTodosStore } from '@/stores/todos'
// 宣言
const todos = useTodosStore()
// --- stateの値をレスポンシブで参照する方法
const { todos, count } = storeToRefs(todos)
// --- actionは分割代入して使える
const { increment } = todos
// --- stateの修正方法3つ
// 1. 修正
counter.count++
// 2. $patch 利用
counter.$patch({ count: counter.count + 1 })
// 3. action 이용
counter.increment()
</script>
<template>
<!-- Storeのstateに直接アクセス -->
<div>Current Count: {{ counter.count }}</div>
</template>
Pinia 基本構造
- 基本構造説明 Option Store方式
- 既存と同様state, getters, actionsを直感的に表現する
- stores/todos-store.js
-
import { defineStore } from 'pinia' export const useTodosStore = defineStore('todos', { //-- storeの名前 state: () => ({ /** @type {{ text: string, id: number, isFinished: boolean }[]} */ todos: [], /** @type {'all' | 'finished' | 'unfinished'} */ filter: 'all', // type will be automatically inferred to number nextId: 0, count: 0 }), getters: { finishedTodos(state) { return state.todos.filter((todo) => todo.isFinished) }, unfinishedTodos(state) { return state.todos.filter((todo) => !todo.isFinished) }, filteredTodos(state) { if (this.filter === 'finished') { return this.finishedTodos } else if (this.filter === 'unfinished') { return this.unfinishedTodos } return this.todos }, }, actions: { increment() { this.count++ }, addTodo(text) { this.todos.push({ text, id: this.nextId++, isFinished: false }) }, }, })
State (Vue)
- 基本的にインスタンスを通じてstateに接近し読み書きできる
- ただし, stateに予め定義しておくべき
const store = useStore() store.count++
- 初期化(Option Store方式のみ可能, Setup Store 方式は直接生成するべき)
-
const store = useStore() store.$reset()
- state 変更
- 直接変更
const store = useStore() store.count++
- patch利用
const store = useStore() store.$patch({ count: store.count + 1, age: 120, name: 'DIO', })
- arrayを修正(push, remove, spliceなど)するケースならmutationをグループ化させることも可能
const store = useStore() store.$patch((state) => { state.items.push({ name: 'shoes', quantity: 1 }) state.hasChanged = true })
- 直接変更
- state変更時には注意
-
// ❌ $stateを使えない store.$state = { count: 24 } // ⭕ 内部的に $patch()を呼び出し store.$patch({ count: 24 })
- state 変更追跡 (subscribe, 購読)
-
<script setup> const someStore = useSomeStore() // この追跡は componentがunmountされたあとでも維持される someStore.$subscribe(callback, { detached: true }) </script>
State (Pinia)
- stateの基本構造(Option Store 方式)
-
state: () => { return { // 最初は空いているlistの場合 userList: [] as UserInfo[], // まだloadされていないデータの場合 user: null as UserInfo | null, } }, interface UserInfo { name: string age: number }
- State インターフェースを利用する場合(Option Store 方式)
-
interface State { userList: UserInfo[] user: UserInfo | null } export const useUserStore = defineStore('user', { state: (): State => { return { userList: [], user: null, } }, }) interface UserInfo { name: string age: number }
- state 変更追跡 (subscribe, 購読)
-
import { MutationType } from 'pinia' cartStore.$subscribe((mutation, state) => { mutation.type // 'direct' | 'patch object' | 'patch function' // same as cartStore.$id mutation.storeId // 'cart' // only available with mutation.type === 'patch object' mutation.payload // patch object passed to cartStore.$patch() // 変更されるたびに全体の状態をローカルストレージにセット localStorage.setItem('cart', JSON.stringify(state)) })
Getters (Vue)
- gettersに接近
-
<script setup> import { useCounterStore } from './counterStore' const store = useCounterStore() </script> <template> <p>Double count is {{ store.doubleCount }}</p> </template>
- gettersに因数(argument)を渡す
- computed 属性であるためパラメータを伝達することはできないが、許容する方法はある。
<script setup> import { storeToRefs } from 'pinia' import { useUserListStore } from './store' const userList = useUserListStore() // <script setup> 내에서 // getUserById.value에 접근 해야함. const { getUserById } = storeToRefs(userList) </script> <template> <p>User 2: {{ **getUserById(2)** }}</p> </template>
- この方法を使えばgetterはもはやキャッシュされない。単純に呼び出す関数
Getters (Pinia)
- vueの computed, vuexの gettersと類似
- getters の基本構造
-
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), getters: { // 返却タイプを自動的にnumberと推論 doubleCount(state) { return state.count * 2 }, // 返却タイプは、「必ず」明示的に設定する必要がある doublePlusOne(): number { // 全体storeに対する自動完成及びtypings ✨ return this.doubleCount + 1 }, }, })
- gettersに因数(argument) 伝達
- computed 属性なのでパラメータを伝達することはできないが、許容する方法はある。
export const useStore = defineStore('main', { getters: { getUserById: (state) => { return (userId) => state.users.find((user) => user.id === userId) }, }, })
- この方法を使えばgetterはもはやキャッシュされていない、単純に呼び出す関数
- 他のストアのgetterにアクセス
-
import { useOtherStore } from './other-store' export const useStore = defineStore('main', { state: () => ({ // ... }), getters: { otherGetter(state) { const otherStore = useOtherStore() return state.localData + otherStore.data }, }, })
-
Actions (Vue)
- actionsの基本構造
-
<script setup> const store = useCounterStore() // storeで actionを呼び出す store.randomizeCounter() </script> <template> <button @click="store.randomizeCounter()">Randomize</button> </template>
- action 変更追跡(subscribe、購読)
-
<script setup> const someStore = useSomeStore() //この購読は、コンポーネントがunmountされた後も維持される someStore.$onAction(callback, true) </script>
Actions (Pinia)
- actions の基本構造
-
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), actions: { // thisに依存するためラムダを使えない increment() { this.count++ }, randomizeCounter() { this.count = Math.round(100 * Math.random()) }, }, })
- 違うstoreの actionsにアクセス
-
import { useAuthStore } from './auth-store' export const useSettingsStore = defineStore('settings', { state: () => ({ preferences: null, // ... }), actions: { async fetchUserPreferences() { const auth = useAuthStore() if (auth.isAuthenticated) { this.preferences = await fetchPreferences() } else { throw new Error('User must be authenticated') } }, }, })
- action変更追跡(subscribe、購読)
-
const unsubscribe = someStore.$onAction( ({ name, // actionの名前 store, // storeインスタンス(例:someStore) args, // actionに伝達されるパラメータ配列 after, // action 返却またはresolve後のhook onError, // action throw あるいはrejenct時のhook }) => { // 特定のaction呼び出しに対する共有変数(shared variable) const startTime = Date.now() // このコードは、storeに対するaction実行前にトリガーされる console.log(`Start "${name}" with params [${args.join(', ')}].`) // このコードはactionが成功し、完全に実行された後にトリガーされる // promisedを返すまで待つ after((result) => { console.log( `Finished "${name}" after ${ Date.now() - startTime }ms.\nResult: ${result}.` ) }) // action throw あるいはrejenct時に実行 onError((error) => { console.warn( `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.` ) }) } ) // listnerを手動で除去 unsubscribe()
コメント
コメントを投稿