Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

ABC5 ストア

例題を勉強したサイトを失念してしまった。思い出したらリンクを張りたい‥。

検索して見つかりました。この記事です。

qiita.com

以下はこの記事を自分で実装してみたメモです。

今、カウンター情報を各コンポーネントで共通化したいと考える。

次のようなクラスを生成する。状態としての情報が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>