【Vue.js】vuexを使ってデータを管理する
はじめに
状態管理ライブラリのvuexを使ってデータを管理します。
vuexの設定
まずはvuexをインストールします。
$ yarn add vuex
vuexの設定ファイルを作成します。
$ touch app/javascript/store/index.js
import Vue from 'vue' import Vuex from 'vuex' import axios from '../plugins/axios' // axiosを使ってapi通信でデータを取ってくるのでaxiosをインポートします Vue.use(Vuex) // モジュールシステムを使う際に必須 export default new Vuex.Store({ state: { // stateで空のtasksを定義 tasks: [] }, getters: { // getterでstateのtasksにアクセスできる tasks: state => state.tasks }, mutations: { // mutationsでstateの状態を変更する setTasks: (state, tasks) => { state.tasks = tasks }, addTask: (state, task) => { state.tasks.push(task) } }, actions: { // actionsでapi通信でのデータ取得などの処理を書く fetchTasks({ commit }) { axios.get('tasks') // axiosを使って'/tasks'にgetリクエストを送る .then(res => { commit('setTasks', res.data) // mutationsの'setTasks'を呼び出して、第二引数に取得したタスク一覧データを渡す }) .catch(err => console.log(err.response)); }, createTask({ commit }, task) { return axios.post('tasks', task) // axiosで'/tasks'にpostリクエストを送る .then(res => { commit('addTask', res.data) // mutationsの'addTask'を呼び出して、第二引数で取得したtaskのデータを渡す }) } }, })
コンポーネントを修正
<template> <div> <div class="d-flex"> <div class="col-4 bg-light rounded shadow m-3 p-3"> <div class="h4">TODO</div> <div v-for="task in tasks" :key="task.id" :id="'task-' + task.id" class="bg-white border shadow-sm rounded my-2 p-4" @click="handleShowTaskDetailModal(task)"> <span>{{ task.title }}</span> </div> <button @click="handleShowTaskCreateModal" type="button" class="btn btn-secondary"> タスクを追加 </button> </div> </div> <div class="text-center"> <router-link :to="{ name: 'TopIndex' }" class="btn btn-dark mt-5">戻る</router-link> </div> <transition name="fade"> <TaskDetailModal v-if="isVisibleTaskDetailModal" @close-modal="handleCloseTaskDetailModal" :task="taskDetail" /> </transition> <transition name="fade"> <TaskCreateModal v-if="isVisibleTaskCreateModal" @close-modal="handleCloseTaskCreateModal" @create-task="handleCreateTask" /> </transition> </div> </template> <script> import { mapGetters, mapActions } from 'vuex' // vuexで定義したgetterとacitonsをインポート import TaskDetailModal from './components/TaskDetailModal' import TaskCreateModal from './components/TaskCreateModal' export default { components: { TaskDetailModal, TaskCreateModal }, name: "TaskIndex", data() { return { taskDetail: {}, isVisibleTaskDetailModal: false, isVisibleTaskCreateModal: false } }, computed: { ...mapGetters([ 'tasks' ]) // mapGettersヘルパーを使ってcomputed(算出プロパティ)とマッピングさせる // stateのtasksの値が変わると更新される }, created() { this.fetchTasks(); // actionsで定義した'fetchTasks'メソッドを呼び出す }, methods: { ...mapActions([ 'fetchTasks', 'createTask' ]), // マッピングさせて直接storeのメソッドを呼べるようにする async handleCreateTask(task) { try { this.createTask(task); // actionsで定義した'createTask'メソッドを呼び出す this.handleCloseTaskCreateModal(); } catch(error) { console.log(error) } }, handleCloseTaskDetailModal() { this.isVisibleTaskDetailModal = false; this.taskDetail = {}; }, handleShowTaskDetailModal(task) { this.isVisibleTaskDetailModal = true; this.taskDetail = task; }, handleCloseTaskCreateModal() { this.isVisibleTaskCreateModal = false; }, handleShowTaskCreateModal() { this.isVisibleTaskCreateModal = true; }, } } </script> <style scoped> .fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter, .fade-leave-to { opacity: 0; } </style>