LoginSignup
14
10

More than 3 years have passed since last update.

[Rails+Vue.js]に係るCRUD入門〜Part5: Vuex設定編〜

Last updated at Posted at 2019-08-22

Rails+Vue.js+Webpackerによる「Create, Read, Update, Destroy」処理のチュートリアルを記述する。
なお,前提知識として,Railsチュートリアル終了程度を想定する。

<概要>

■ 本記事の内容

■ 記事共通

<本文>

■ Vuexの導入

○1:Vuexをインストール

$ yarn add vuex

○2:[store.js]を作成

app/javascript/store/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import router from '../router/router.js'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {}
})

○3:[application.js]に[store.js]を登録

app/javascript/packs/application.js
import Vue    from 'vue'
import App    from './App.vue'
import Router from '../router/router.js'
import Store  from '../store/store.js'

const app = new Vue({
   el: '#app',
   router: Router,
   store: Store,
   render: h => h(App)
})

■ [fetchBooks]関連を移行

○1:[store.js]を修正

app/javascript/store/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import router from '../router/router.js'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  // [state]がコンポーネントにおける[data]に相当
  state: {
    books: []
  },
  // [mutations]がコンポーネントにおける[methods]に相当
  mutations: {
    fetchBooks(state) {
      state.books = [];
      axios.get('/api/books').then((res) => {
        for(var i = 0; i < res.data.books.length; i++) {
          state.books.push(res.data.books[i]);
        }
      }, (error) => {
        console.log(error);
      });
    }
  },
})

○2:[HomeBook.vue]を修正

app/javascript/pages/BookHome.vue
...
<script>
...
    data: function() {
      return {
        bookInfo: {},
        bookInfoBool: false,
        // [store.js]に移行するため,[books]を削除
      }
    },
    computed: {
       // [store.js]から[books]を呼び出して,[BookHome.vue]のdata[books]に格納
      books() {
       return this.$store.state.books
      }
    },
    mounted: function() {
      // [fetchBooks]を[store.js]から呼び出すため,コード修正
      this.$store.commit('fetchBooks')
    },
    methods: {
      // [store.js]に移行するため,[fetchBooks]を削除
      ...
    }
...

■ [setBookInfo]関連を移行

○1:[store.js]を修正

app/javascript/store/store.js
...
  state: {
    books: [],
    bookInfo: {},
    bookInfoBool: false
  },
  mutations: {
    ...
    setBookInfo(state, { id } ) {
      axios.get(`api/books/${id}.json`).then(res => {
        state.bookInfo = res.data;
        state.bookInfoBool = true;
      });
    }
  }
})

○2:[HomeBook.vue]を修正

app/javascript/pages/BookHome.vue
<script>
...
    // [data:]は,全て削除
    computed: {
     books() {
       return this.$store.state.books
     },
     // [bookInfo, bookInfoBool]を追加
     bookInfo() {
       return this.$store.state.bookInfo
     },
     bookInfoBool() {
       return this.$store.state.bookInfoBool
     }
    },
    ...
    methods: {
    // [setBookInfo]を[store.js]から呼び出すため,コード修正
      setBookInfo(id) {
        this.$store.commit('setBookInfo', { id })
      },
...

■ [deleteBook]関連を移行

○1:[store.js]を修正

app/javascript/store/store.js
...
  mutations: {
    ...
    deleteBook(state, { id } ) {
      axios.delete(`/api/books/${id}`).then(res => {
        state.bookInfo = '';
        state.bookInfoBool = false;
      });
    }
...

○2:[HomeBook.vue]を修正

app/javascript/pages/BookHome.vue
<script>
...
    methods: {
      setBookInfo(id) {
        this.$store.commit('setBookInfo', { id })
      },
      // [deleteBook]のコードを修正
      deleteBook(id) {
        this.$store.commit('deleteBook', { id })
        this.$store.commit('fetchBooks')
      },
    }
...

■ ヘルパー関数による省略技法

app/javascript/store/store.js
...
<script>
  import axios from 'axios'
  import { mapState } from 'vuex'

  export default {
    name: 'BookHome',
    computed: mapState([
      'books',
      'bookInfo',
      'bookInfoBool',
    ]),
...

/* 上記のコードと同等
 ~Ver.1:mapStateを使用して,異なるデータ名に格納したい場合~
    computed: mapState({
      books: 'books',
      bookInfo: 'bookInfo',
      bookInfoBool: 'bookInfoBool'
    })

 ~Ver.2:デフォルト~
    computed: {
      books() {
        return this.$store.state.books
      },
      bookInfo() {
        return this.$store.state.bookInfo
      },
      bookInfoBool() {
        return this.$store.state.bookInfoBool
      }
    }
*/

■ 特記事項

○1:[action,getter]について
 今後チュートリアルで必要性が出てきたら追記します。

○2:Vuexの状態管理下に置くデータについて
 Vuexの機能上,全てのデータを管理下に置くことは可能であり,複雑でもModuleを使用したら実装できるかと思います。
 しかし,一つのコンポーネントでしか使用しないデータを共通の管理下に置くことは,冗長になり,管理が大変になることが予想されますので,以下の情報が判断の参考になるかと思い引用します。

  • ステートに適したデータ
    • サーバーからデータを取得中かどうかを表すフラグ
    • ログイン中のユーザー情報など,アプリケーション全体で使用されるデータ
    • ECサイトにおける商品の情報など,アプリケーションの複数の場所で使用される可能性のあるデータ
  • コンポーネント側で持つべきデータ
    • マウスポインタがある要素の上に存在するかどうかを表すフラグ
    • ドラッグ中の要素の座標
    • 入力中のフォームの値

【引用:Vue.js入門~基礎から実践アプリケーション開発まで~ 245-246.】

〜Part5: Vuex設定編終了〜
〜Part6: ユーザー登録&ログイン編へ進む〜

14
10
2

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
14
10