Vue.js

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

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

この記事の目次
  1. Vuex + axiosでの基本的なAPI操作方法
  2. データの初期値を設定する
  3. 変更があったときに再評価されるようにする
  4. コンポーネント
  5. APIからデータを取得して表示する
  6. データを取得するためのactions
  7. データを取得するためのmutations
  8. コンポーネントで表示
  9. データを追加する
  10. データを追加するためのactions
  11. データを追加するためのmutations
  12. コンポーネント
  13. データを削除する
  14. データを削除するためのactions
  15. データを削除するためのmutations
  16. コンポーネント
  17. データをフィルターする
  18. データをフィルターするためののactions
  19. コンポーネント
  20. データをアップデートする
  21. データをアップデートするためのactions
  22. データをアップデートするためのmutations
  23. コンポーネント

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だけがトグルします。