ABC5 ストア
例題を勉強したサイトを失念してしまった。思い出したらリンクを張りたい‥。
検索して見つかりました。この記事です。
以下はこの記事を自分で実装してみたメモです。
今、カウンター情報を各コンポーネントで共通化したいと考える。
次のようなクラスを生成する。状態としての情報がreactiveになっている点に注意。
import { reactive } from '@vue/composition-api'; export default function counterStore() { const state = reactive({ count:0 }) return { get count() { return state.count; }, increment() { state.count += 1; }, decrement() { state.count -= 1; } } }
そして、このストアを共有するコンポーネントをテンプレートで囲む用のコンポーネントとして、 CounterProviderコンポーネントを作成する。
<template> <div> <slot /> </div> </template> <script lang="ts"> /* eslint-disable */ import { defineComponent, provide } from '@vue/composition-api' import CounterKey from './counter-key'; import counterStore from '../stores/counter'; export default defineComponent({ setup() { /// ストアを生成しキーを設定する。 provide(CounterKey, counterStore()); return {}; } }) </script>
このprovideというのがポイントでこのためにキーを定義しておく。
/* eslint-disable */ import {InjectionKey} from "@vue/composition-api" import {CounterStore} from '../stores/counter'; /// コンポーネント間で共通に使うキーの定義 const CounterKey: InjectionKey<CounterStore> = Symbol('CounterStore'); export default CounterKey;
使うときはこのようにテンプレートを入れ子にする。
<counter-provider> <InjectedDecrementButton /> <InjectedCounterDisplay /> <InjectedIncrementButton /> </counter-provider>
各、入れ子にしたテンプレートではキーをInjectでカウンターを取り出せる。
<template> <span class="count"> {{ count}} </span> </template> <script lang="ts"> /* eslint-disable */ import { defineComponent, inject, computed } from '@vue/composition-api'; import CounterKey from './counter-key'; export default defineComponent({ name:"InjectedCounterDisplay", setup() { const counter = inject(CounterKey); if (!counter) { throw new Error(`${CounterKey} is not provided`); } const count = computed(() => counter.count); return { count } } }) </script>
<template> <button v-on:click="increment"> + </button> </template> <script lang="ts"> /* eslint-disable */ import { defineComponent, inject } from '@vue/composition-api' import CounterKey from './counter-key'; export default defineComponent({ name:"InjectedIncrementButton", setup() { /// ストアを取得 const counter = inject(CounterKey); if (!counter) { throw new Error(`${CounterKey} is not provided`); } return { increment: counter.increment } } }) </script>
<template> <button v-on:click="decrement"> - </button> </template> <script lang="ts"> /* eslint-disable */ import { defineComponent, inject } from '@vue/composition-api' import CounterKey from './counter-key'; export default defineComponent({ name:"InjectedDecrementButton", setup() { /// ストアを取得 const counter = inject(CounterKey); if (!counter) { throw new Error(`${CounterKey} is not provided`); } return { decrement: counter.decrement } } }) </script>