Nuxt.jsとVuexでCRUDの編集機能を実装する

#目次
[1.なぜ編集機能のみなのか](#1-なぜ編集機能のみなのか)
[2.実装](#2-実装)
[3.編集を実装する](#3-編集を実装する)
[4.つまずきポイント](#4-つまずきポイント)
[5.おわりに](#5-おわりに)

#1. なぜ編集機能のみなのか
Vue.jsやNuxt.jsで編集機能を探していたのですが、自分のやりたい編集機能を実装している記事がなかったので、質問サイトを利用したり、他の記事を部分的に参考にしたものをまとめようと思いました。

※ CRUDの他の機能は解説してくれているところもたくさんありますし、Nuxtの公式でも十分対応可能でしたので敢えてここで記載する必要はないと判断しました。

-環境
・Vuetify
・Nuxt.js 2.15

[Nuxt.js公式Todoリスト作成参考](https://ja.nuxtjs.org/docs/2.x/directory-structure/store)

#2. 実際の編集画面
① 投稿したリストの編集ボタンをクリックすると表示が切り替わる
② 投稿した内容が入力欄に表示される
③ 内容を変更して保存すると元のリストの位置に結果が反映される
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/1d196f66-50dd-dd5a-ab36-4a4d5e61eaa0.gif)
#3. 編集を実装する

**template**

```Vue.js
      <v-row v-for="(todo,index) in todos" :key="index">
        <v-text-field
          filled
          readonly
          :value="todo.text"
          class="mr-2"
          auto-grow
        />
        <v-menu
          top
          rounded
        >
          <template #activator="{ on, attrs }">
            <v-btn
              v-bind="attrs"
              icon
              class="mt-3"
              v-on="on"
            >
              <v-icon>
                mdi-dots-vertical
              </v-icon>
            </v-btn>
          </template>
          <v-list>
            <v-list-item
              link
              @click="toEdit(todo)"
            >
              <v-list-item-title>
                <v-icon>mdi-pencil</v-icon>
                編集
              </v-list-item-title>
            </v-list-item>
          </v-list>
          <v-list>
            <v-list-item
              link
              @click="removeTodo(todo)"
            >
          </v-list>
        </v-menu>
      </v-row>
      <v-text-field
        v-model="itemText"
        filled
        color="pink lighten-3"
        auto-grow
      />
      <v-row>
        <v-col>
          <v-btn
            :disabled="disabled"
            @click="addTodo"
          >
            保存
          </v-btn>


```
**表示する値**
こちらはVuexを使用して配列で管理しています。v-forを使用して取り出すことで更新した値がリアクティブに反映されます。注意しなくてはいけないのが、使用するメソッドによってはリアクティブに反映されないということです。
・Vuexで配列の値を管理
・v-bind:valueで値を表示している。

[Vue.js配列の変化を抽出](https://jp.vuejs.org/v2/guide/list.html#%E9%85%8D%E5%88%97%E3%81%AE%E5%A4%89%E5%8C%96%E3%82%92%E6%A4%9C%E5%87%BA)

**編集ボタンの実装**
v-menuはVuetifyを使用しています。詳しくは公式サイトを確認ください
・　編集ボタンを押すとtoEditメソッドに発火
・toEditの引数(todo)でリストの位置を取得。todoはv-forでリストレンダリングした配列。つまりユーザーがクリックしたリストがtoEditの引数になる

[Vuetify参考](https://vuetifyjs.com/ja/components/menus/)
**script**

```Vue.js
<script>
export default {
  data () {
    return {
      itemText: '',
      selectedTodo: [],
    }
  },

  computed: {
    todos () {
      return this.$store.state.todos.list
    },
    disabled () {
      return this.itemText.length === 0
    }
  },

  methods: {
    addTodo () {
      if (this.selectedTodo.done === false) {
        this.$store.commit('todos/add', this.itemText)
        this.itemText = ''
      } else {
        this.$store.commit('todos/edit', { todo: this.selectedTodo, text: this.itemText })
        this.itemText = ''
        this.$store.commit('todos/toggle', this.selectedTodo)
      }
    },
    toEdit (todo) {
      this.selectedTodo = todo
      this.itemText = todo.text
      this.$store.commit('todos/toggle', todo)
    }
  }
}
</script>
```
**編集実行の流れ**
① 編集ボタンを押すとtoEditメソッドが実行される。
② ``this.selectedTodo = todo``でdataにあるselectedTodoにユーザーが選択したtodoリストを保存する
③ ``this.itemText = todo.text``では追加したリストを表示させる
④``this.$store.commit('todos/toggle', todo)``ここではステータスを変更している。ここではどのリストが編集されているか判断するためにフラグとして使用している　(この辺は公式を引用)

**this.$store.commit('todos/toggle', todo)**
``
toggle (state, todo) {
    todo.done = !todo.done
  }
``

**編集後に保存ボタンを押す**
① 保存ボタンを押すと``addTodo``メソッドが実行される
② selectedTodoのフラグ``this.selectedTodo.done === false``で確認してfalseの場合は通常通り追加するだけ。(doneには編集中かどうかのフラグある)
先ほどの``his.$store.commit('todos/toggle', todo)``で編集ボタンを押したらtrueになるように設定しています
③ ``this.selectedTodo.done === false``じゃない場合。つまり``this.selectedTodo.done``がtrueの場合に編集用のメソッドが実行されます。
編集用のメソッドは他のCRUDのメソッドと同様にVuexに保存しています。この辺はお好みだと思います。
先ほど少し触れましたが、Nuxt又はVueでは配列をリクティブに反映できるメソッドとそうでないメソッドがあります。``splace``はリアクティブに反映できるメソッドの範囲に入っています。
**store**

``` 
  // 編集を反映
  edit (state, { todo, text }) {
    state.list.splice(state.list.indexOf(todo), 1, { text })
  },

```

#4. つまずきポイント
・ mutationにデータを送る際に引数を３つ持たせていましたが、公式にも書いてある通り、mutationの引数は二つまでです。オブジェクト形式にして値を渡すことで解決しました。

[Vuexの引数について](https://vuex.vuejs.org/ja/guide/mutations.html)

・ リストの追加の際に編集からの送信と通常の追加でどう実装しようか悩みました。当初は専用のフラグを用意しましたが、リストを通常追加する際にdoneにステータスを追加することで解決しました。
#5. おわりに
次はデータをVuex→ DBに保存したいと考えています。Vuexのactionsを使用して非同期処理を行います。