LoginSignup
7
2

More than 1 year has passed since last update.

【Vuex】モジュール分割してストアを管理する方法【Typescript】

Last updated at Posted at 2022-10-28

始めに

本記事はこちらの記事の内容を発展させたものです。
良ければご覧ください。
見なくても理解には問題ないです。

開発環境

MacBook Air (M1, 2020)
npm 8.18.0

本記事の内容

  • 前提
  • モジュール分割
  • vueファイルへの変更の反映

前提

以下の単純なアプリケーションをVuexでモジュール分割して、管理します。
あるのは、配列への要素の追加と、draggableのメソッドのみです。

TodoListView.vue(モジュール化前)
<script setup lang="ts"> 
    import { computed, reactive } from 'vue';
    import { useStore } from '../store'
    import draggable from 'vuedraggable';
    
    type TodoList = {
        id?: number;
        description: string;
    };

    const list = reactive({
        description:''
    })

    const clearForm = () => {
        list.description = ""
    };

    const store = useStore()

    const addList = () =>{
        store.dispatch('addList', {
            id: Math.floor(Math.random() * 100000),
            description: list.description
        });
        clearForm();
    }

    const todoLists = computed<TodoList[]>({
        get: () => store.getters['todoLists']
        set: val=> {
            store.dispatch('dragList', val)
        }
    })
</script>

<template>
    <div>
        <h2>タスク管理</h2>
        <form @submit.prevent="addList">
            <input type="text" id="description" v-model="list.description" /><br>
            <input type="submit" value="submit"/>
        </form>
        <hr />
        <draggable v-model="todoLists" group="list" item-key="id" class="list-index" >
            <template #item="{element}">
                <div class="list">
                    <p>{{element.description}}</p>
                </div>
            </template>
        </draggable>
    </div>
</template>

モジュール分割

モジュールで分割をするためには、二つのことが必要です。
モジュール化したファイルとモジュール化したファイルの呼び込み先です。
その2つのファイルを作成していきます。

以下手順を記載します。
①ストアファイルをモジュール化
②モジュール化したファイルの呼び込み

順に解説していきます。

①モジュール化

モジュール化したファイルの変更点としては、一つだけです。

  • Module,
  • ActionTree,
  • MutationTree,
  • GetterTree

上記4つのオブジェクトの作成です。

src/store/todo-list/index.ts
import { Module, ActionTree, MutationTree, GetterTree } from "vuex";

//型定義
type RootState={
    version: string
}

type TodoListsState = {
    todoLists: TodoList[];
};

type TodoList = {
    id?: number;
    description: string;
};

//ローカルストレージから情報を取得
const savedLists = localStorage.getItem('todo-lists')

export const state: TodoListsState = {
    todoLists: savedLists ? JSON.parse(savedLists): []
};

//GetterTreeのオブジェクトを用意
const getters: GetterTree<TodoListsState, RootState> = {
    getTodoLists: state => state.todoLists,
    getTodoListById: state => (list_id: number) =>state.todoLists.find(list=>list.id === list_id)!
};

//MutationTreeのオブジェクトを用意
const mutations: MutationTree<TodoListsState> = {
    addList(state, payload: TodoList){
        state.todoLists.push(payload)
    },
    dragList(state, payload: TodoList[]) {
        state.todoLists = payload
    },
};

//ActionTreeのオブジェクトを用意
const actions: ActionTree<TodoListsState, RootState> = {
    addList({commit}, payload: TodoList) {
        commit('addList', payload)
    },
    dragList({commit}, payload: TodoList[]) {
        commit('dragList', payload)
    },
}

export const TodoListsModule: Module<TodoListsState, RootState> = {
    namespaced: true,
    state,
    getters,
    actions,
    mutations,
};

②作成したモジュールの呼び込み

src/store/todoList
import { InjectionKey } from 'vue';
import { createStore, Store, useStore as baseUseStore } from "vuex";
import { TodoListsModule } from '../store/TodoList'

//型定義
type RootState={
    version: string
}

export const store = createStore<RootState>({
  state: {
    version: '1.0.0' //超単純なプロパティを設定。
  },
  modules: {
    //importをしたモジュールを記載
    todoLists: TodoListsModule
  },
});

export const key: InjectionKey<Store<RootState>> = Symbol();

export const useStore = () => {
    return baseUseStore(key);
}

//ローカルストレージ。モジュール化したstateを呼び込みたいときは、"state.モジュール名.配列名"となる。
store.subscribe((mutation, state: any) => {
  localStorage.setItem('todo-lists', JSON.stringify(state.todoLists.todoLists))

Vueファイルへの反映

モジュール名を設定したら、以下のようにコードを変更してください。

TodoListView.vue(変更後)
<script setup lang="ts"> 
    import { computed, reactive } from 'vue';
    import { useStore } from '../store'
    import draggable from 'vuedraggable';
    
    type TodoList = {
        id?: number;
        description: string;
    };

    const list = reactive({
        description:''
    })

    const clearForm = () => {
        list.description = ""
    };

    const store = useStore()

    const addList = () =>{
        //モジュール化した場合、呼び込みたいものの前にモジュール名/をつける。
        store.dispatch('todoLists/addList', {
            id: Math.floor(Math.random() * 100000),
            description: list.description
        });
        clearForm();
    }

    const todoLists = computed<TodoList[]>({
        //こちらも同様
        get: () => store.getters['todoLists/getTodoLists']
        set: val=> {
            //こちらも同様
            store.dispatch('todoLists/dragList', val)
        }
    })
</script>

<template>
    <div>
        <h2>タスク管理</h2>
        <form @submit.prevent="addList">
            <input type="text" id="description" v-model="list.description" /><br>
            <input type="submit" value="submit"/>
        </form>
        <hr />
        <draggable v-model="todoLists" group="list" item-key="id" class="list-index" >
            <template #item="{element}">
                <div class="list">
                    <p>{{element.description}}</p>
                </div>
            </template>
        </draggable>
    </div>
</template>
7
2
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
7
2