Vuex + axiosでの基本的なAPI操作方法(CRUD)追加・削除・更新・フィルター

Vue.js

Vuex + axiosを使って、追加・削除・更新・フィルターといった基本的なAPI操作方法(CRUD)を紹介します。

Vuex + axiosでの基本的なAPI操作方法

vuexの基本的な使い方の通りにstoreフォルダの中にmodulesフォルダを作成し、その中にtodos.jsを作成します。

index.js

import Vuex from 'vuex'
import Vue from 'vue'
import todos from './modules/todos'

// Load Vuex
Vue.use(Vuex)

// Create store
export default new Vuex.Store({
  modules: {
    todos
  }
})

todos.js

import axios from 'axios'

const state = {}

const getters = {}

const actions = {}

const mutations = {}

export default {
  state,
  getters,
  actions,
  mutations
}

axiosをインポートして、使うものを宣言してエクスポートしておきます。

あとはここに処理を記述していきます。

データの初期値を設定する

dataを管理するところなので、次のように記述します。

const state = {
  todos: [],
}

変更があったときに再評価されるようにする

算出プロパティと同じように動くgettersを使ってデータに変更があった場合に再評価できるようにします。

const getters = {
  allTodos: (state) => state.todos
}

コンポーネント

import {mapGetters } from 'vuex'
export default {
  name: 'Todos',
  computed: mapGetters(['allTodos']),
}

APIからデータを取得して表示する

actionsとmutationsを設定します。

データを取得するためのactions

const actions = {
  // Set todo
  async fetchTodos({ commit }) {
    const response = await axios.get('https://....com/todos')
    commit('setTodos', response.data);
  },
...
}

actions→mutations→stateという流れを作ることで、actionsで複数のcommitを設定できます。
APIからデータを取得するにはactionsで非同期処理async-awaitを使います。
axiosでgetしたものをresponseに格納します。
コンソールなどでresponseの中身を確認します。
そしてデータに、response.dataなどとするとアクセスできることを確認したら、commitします。

データを取得するためのmutations

const mutations = {
  // settodo
  setTodos: (state, todos) => (state.todos = todos),
}

actionsで設定したオブジェクトにアクセスして、todosのデータをstate.todosに格納します。

コンポーネントで表示

そしてあとはtemplateタグで表示します。

<div class="todos">
  <div
    v-for="todo in allTodos"
    :key="todo.id"
    >
    {{todo.title}}
  </div>
</div>

データを使うには、mapGettersとmapActionsをインポートして設定しておく必要があります。

import {mapGetters, mapActions } from 'vuex'

export default {
  ...
  methods: {
    ...mapActions(['fetchTodos']),
  },
  ...
  created () {
    this.fetchTodos()
  }
}

createdはVueインスタンスの作成が完了して、DOMがまだ作られていない状態であり、mountedではDOMが作成された直後の状態です。
createdの中でAPIなどの外部からのデータを受け取っても、dataオブジェクトはすでにリアクティブになっているのでcreated()を使います。

データを追加する

データを追加するためのactions

  // Add todo
  async addTodo({commit}, title) {
    const response = await axios.post('https://....com/todos',
    { title, completed: false})

    commit('newTodo', response.data)
  },

追加するときは、postを使います。
そして、追加したいデータを第二引数にオブジェクトで設定します。
commit部分はfetchと大体同じです。

データを追加するためのmutations

  // Addtodo
  newTodo: (state, todo) => state.todos.unshift(todo),

todosの中に、新しいtodoをunshiftやpushすることで追加することができます。

コンポーネント

import {mapActions} from 'vuex'

export default {
  name: 'AddTodo',
  data() {
    return {
      title: '',
    }
  },
  methods: {
    ...mapActions(['addTodo']),
    onSubmit(e) {
      e.preventDefault()
      this.addTodo(this.title)
    }
  }
}

データを削除する

データを削除するためのactions

  // delete todo
  async deleteTodo({commit}, id) {
    await axios.delete(`https://....com/todos/${id}`);
    commit('removeTodo', id);
  },

削除には、deleteを使います。
よくidを渡してそれを削除するという方法が使われます。

データを削除するためのmutations

  // deletetodo
  removeTodo: (state, id) => state.todos = state.todos.filter(todo => todo.id !== id),

filter()を使って、idが一致するもの以外の配列を取得することで、そのidの入っていない配列を作成(削除)することができます。

コンポーネント

  methods: {
    ...mapActions(['fetchTodos', 'deleteTodo']),
...
  },

methodsのなかのmapActionsに作成したdeleteTodoを追加することで使えるようになります。

<button class="delete" @click="deleteTodo(todo.id)">削除</button>

データをフィルターする

データをフィルターするためののactions

  // Filter todo
  async filterTodos( {commit}, e) {
    // Get selected numver
    const limit = parseInt(e.target.options[e.target.options.selectedIndex].innerText)
    const response = await axios.get(`https://....com/todos?_limit=${limit}`);
    commit('setTodos', response.data);
  },

上は表示数でフィルターする場合です。
limitなどでurlに受け取る数字を格納できる変数を作成します。
selectのoptionタグなどの数字を取得して使いたい場合は、上のようにJavaScriptを記述入します。

なおmutationsは不要となります。

コンポーネント

<select @change="filterTodos($event)">
  <option value="100">100</option>
  <option value="50">50</option>
  <option value="20">20</option>
</select>

このようにoptionのinnnterTextを取得できるように記述します。

  methods: mapActions(['filterTodos'])

忘れずにscriptタグにmapActionsを追加します。

データをアップデートする

データをアップデートするためのactions

  // update todo
  async updateTodo({commit}, updTodo) {
    const response = await axios.put(`https://....com/todos/${updTodo.id}`, updTodo);
    commit('updateTodo', response.data)
  }

データの更新にはputを使います。
アップデートするidを設定して、第二引数でtodoを渡します。

データをアップデートするためのmutations

  // updatetodo
  updateTodo: (state, updTodo) => {
    const index = state.todos.findIndex(todo => todo.id === updTodo.id);
    if (index !== -1) {
      state.todos.splice(index, 1, updTodo);
    }

データを更新するためには、まずidを探します。
todoの中のidと更新したいもののidが一致するものと指定したい場合、
find()やfindIndex()を使います。
条件を満たす要素がない場合、-1を返すので、-1でない場合のみ、処理できるようにif文を設定します。
使い分けは、JavaScriptの配列メソッド、どれを使えばいいのか?を参考にしてみてください。

コンポーネント

  methods: {
    ...mapActions(['fetchTodos', 'deleteTodo', 'updateTodo']),
    // Update todo
    onDblClick(todo) {
      const updTodo = {
        id: todo.id,
        title: todo.title,
        completed: !todo.completed
      }

      this.updateTodo(updTodo)
    }
  },

忘れずにmapActionsに追加します。
上の例ではダブルクリックしたらcompeltedだけがトグルします。

Vue.js

Posted by devsakaso