【Vue】Vuex ~ 入門編 ~

■ はじめに

Vuex (ビューエックス) ってのを扱う。

目次

【1】Vuex とは?
【2】関連用語
 1)Store(ストア)
 2)State(ステート)
 3)Actions(アクション)
 4)Mutations(ミューテーション)
【3】環境設定
 1)Vue.js devtools
 2)vuex-module-decorators
【4】サンプル

【1】Vuex とは?

* データの管理を一元化するためのライブラリ
 => システム全体のグローバル変数みたいなもの
 => コンポーネント間でデータの受け渡しが容易になる
* React でいう Redux
* 読み方は、「ビューエックス」が多いよう

https://forum.vuejs.org/t/vuex/28006/3

【2】関連用語

1)Store(ストア)
https://vuex.vuejs.org/ja/guide/

* アプリケーションの 状態(state) を保持するコンテナ
* グローバルオブジェクトとの違いは、2つ。
 1) リアクティブ(Reactive=反応的な)※
 2) ストアの状態を直接変更せず、ミューテーションを通して行う

※ リアクティブ について

 => 状態が変更されたらViewに反映?
 => 詳細は、以下の公式サイト。

https://jp.vuejs.org/v2/guide/reactivity.html

【自分の勝手なイメージ】

~~~~~~
Store ... イメージ的にStoreクラスに、以下の4つの概念がある感じ
 + State ... 詳細は「2)State(ステート)」
 + Getter ... 状態をVue Componentに返却(Javaでいうゲッター)
 + Actions ... 詳細は「3)Actions(アクション)」
 + Mutations ... 詳細は「4)Mutations(ミューテーション)」
~~~~~~

* 公式サイトよりも以下のページの概念図をみておくといいかも。

https://qiita.com/kouki-iwahara/items/1a75daaa93657b0b56d7

2)State(ステート)

* State = 状態
⇒ 概念的に、アプリケーションの状態(e.g. ログイン情報 など)の実体
⇒ Javaでいうプロパティ

3)Actions(アクション)

* 非同期処理(GETやPOST)や外部APIとのやりとりを行う

4)Mutations(ミューテーション)

* Mutation = 変化、変形
* ステートを更新するために用いられる

【3】環境設定

以下は、必須ではないが、やっとくといいかも、、、

1)Vue.js devtools

Chromeブラウザを使っている場合、デバッグツールとして
「Vue.js devtools」を入れておくと、Storeの中とか覗けて便利らしい。
(使っているVueのバージョンも確認出来ていい!)

以下が詳しい。

https://qiita.com/hashimoto-1202/items/c81f5d4c271eef16d957

設定手順

[1] 以下のサイトからインストール

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hl=ja

[2] 拡張機能の設定画面を開き、
 「ファイルのURLへのアクセスを許可する」にチェックを入れる
[3] ブラウザを再起動。
 => F12などで、デバッグツールを開くと、右側に「Vue」タブがあるはず

2)vuex-module-decorators

vuex-module-decorators ってのを使うと
スマートに書けるので、導入。詳細は、以下のサイトを参照。

https://re-engines.com/2019/07/16/vuex-module-decorators%E3%81%A8typescript%E3%81%A7vuex%E3%82%92%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%81%AB%E6%9B%B8%E3%81%8F/

vuex-module-decorators のインストール

* 以下のコマンドでインストールする。
~~~~~~
npm install -D vuex-module-decorators
~~~~~~

https://github.com/championswimmer/vuex-module-decorators
補足:npm install -D について
https://docs.npmjs.com/cli/v6/commands/npm-install

より、「-D」=「-save-dev (ローカルインストール)」。
-save-dev の詳細は、以下のサイトを参照。

https://qiita.com/heyheyww/items/092fcbc490a249a2d05c

【4】サンプル

あるあるだが、簡単なToDoリストをVuex+TypeScriptで実装する。
(こんなことに、メチャクチャはまった、、、)

https://dk521123.hatenablog.com/entry/2020/12/22/192553

の「例:vue create コマンド」で作成したプロジェクトをベースに行う。

ファイル構成

my-app << 対象プロジェクト
 + src
     + models << 新規追加
      |  + ToDoModel.ts << 新規追加
     + store
      |  + index.ts << もともとあった。そのまま使用。
      |  + todo.ts << 新規追加
     + views
      |  + VuexDemo.vue << 新規追加
      + router
        + index.ts << 修正(VuexDemo.vueを追加。今回は省略)

ToDoModel.ts

export default class ToDoModel {
  Id: string;
  Content: string;
  IsDone: boolean;

  constructor(content: string) {
    this.Id = Date.now().toString()
    this.Content = content;
    this.IsDone = false;
  }
}

todo.ts

import { Module, VuexModule, Mutation, getModule } from 'vuex-module-decorators'
import store from "@/store/index"
import ToDoModel from '../models/ToDoModel'

// 「dynamic:true」にしたら動いた!
@Module({ dynamic:true, store: store, namespaced: true, name: 'todo' })
export default class ToDo extends VuexModule {
  todos: ToDoModel[] = []

  get ToDoList() {
    return this.todos;
  }

  @Mutation
  addToDo(content: string) {
    const todo: ToDoModel = new ToDoModel(content);
    this.todos.push(todo);
  }

  @Mutation
  toggle(todo: ToDoModel) {
    todo.IsDone = !todo.IsDone;
  }
}

export const todoModule = getModule(ToDo)

VuexDemo.vue

<template>
  <div style="margin: 20px;">
    <input placeholder="Add ToDo" @keyup.enter="onKeydownEnter">
    <div class="alert alert-primary" v-show="message">{{ message }}</div>
    <ul>
      <li v-for="(todo, index) in ToDos" :key="index">
        <input type="checkbox" v-model="todo.IsDone" @click="onChanged(todo)">
        <span>{{ todo.Content }}</span>
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { todoModule } from "../store/todo";
import ToDoModel from "../models/ToDoModel";

@Component
export default class VuexDemo extends Vue {
  private message: string;

    constructor() {
      super();
      this.message = "";
    }

  get ToDos(): ToDoModel[] {
    return todoModule.ToDoList;
  }

  private onKeydownEnter(event: Event) {
    if (event.target instanceof HTMLInputElement) {
      const content = event.target.value;
      console.log(`content = ${content}`);
  
      todoModule.addToDo(content);
      event.target.value = "";
    }
  }

  private onChanged(todo: ToDoModel) {
      console.log(`Before = ${todo.IsDone}`);
      todoModule.toggle(todo);
      console.log(`After = ${todo.IsDone}`);
  }
}
</script>

動作確認

npm run server
で実行させて、以下のURLにアクセスする

http://localhost:8080/VuexDemo

参考文献

https://yuutookun.hatenablog.com/entry/2018/07/21/084912
https://re-engines.com/2019/07/16/vuex-module-decorators%E3%81%A8typescript%E3%81%A7vuex%E3%82%92%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%81%AB%E6%9B%B8%E3%81%8F/
https://toragramming.com/programming/nuxt-js/nuxt-typescript-vuex-todo-tutorial/

関連記事

Vue.js ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/04/30/000000
Vue.js ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2020/12/19/000000