Vueのディレクトリの責務について考える - Qiitaの続きです。
ロジックを追加する場所
Vueで業務ロジックを追加する場合、以下の4通りの構成が思い浮かびました。
- SFCのメソッド内に直接書く
- Vuexを使う
- vuex-ormを使う
- モデルを作成する
SFCのメソッド内に直接書く
前回まではこのように書いていましたが、コンポーネント間で同じロジックが書かれたりすることにより保守が大変になります。それを避けるためにutil関数とかを作ったりしても用途不明の関数が大量生産され残念なことに。
(小規模なアプリならこの書き方で問題ないです。)
Vuexで頑張る
複雑な業務ロジックがない場合はVuexでいいかもしれません。(APIを取得してフィルターをかけるだけのような)
ただVuexに依存することになるので、他のFWに変更するとなった場合のコストが大きいです。
vuex-ormを使う
バックエンドのORMのような使用心地、メソッドチェーンでクエリーが記述できるのですごく使いやすいです。(Laravelのormにそっくり)
Vuexの上にさらにライブラリを使うのでもうVueと添い遂げる覚悟が必要そうですね。
モデルを作成する
この方法が現状では一番いいと思っています。Vuexと併せて使うことも可能です。AngularやReactや将来出る新しいFWに変更する場合もスムーズに移行できると思います。
以下の資料が分かりやすいので、ぜひ読んでみてください。
モデルの例
QiitaItemモデルの作成
export default class QiitaItem {
constructor(
public body: string,
public created_at: string,
public title: string,
public url: string,
) {}
shortTitle(): string {
return this.title.substr(0, 20) + '...';
}
}
(TypeScriptのクラスではコンストラクターの引数にアクセス修飾子を付与することで、プロパティの生成と初期化を行なってくれる。)
Repositoryからモデルを返す
import axios from 'axios';
import config from '@/config';
import QiitaItem from '@/models/QiitaItem'
const baseURL = 'https://qiita.com/api/v2/';
const Repository = axios.create({
baseURL,
headers: {
Authorization: 'Bearer ' + config.qiita.token,
},
});
export default {
async getItemsBy(userId: number): Promise<QiitaItem[]> {
let qiitaItems = [];
const { data } = await Repository.get(`users/${userId}/items`);
foreach (qiitaItem of data) {
qiitaItems.push(new QiitaItem(qiitaItem));
}
return qiitaItems;
},
};
コンポーネントからはRespositoryの関数を実行するとModelが返ってくる。(配列のモデル)
import qiitaRepository from '@/repositories/qiitaRepository'
...
const qiitaItems = qiitaRepository.getItemsBy(123);
qiitaItems[0].shortTitle();
ここまでのディレクトリ構成
├── components // ステートフルコンポーネント、ステートレスコンポーネント
├── containers // コンテナコンポーネント
├── repositories // API通信
├── models // モデル達
├── views // ページと1:1
├── App.vue // トップページのコンポーネント
├── main.js // プラグインの使用など
├── router.js // ルーティング
└── store.js // Vuex
シンプルな業務ロジックであれば、repositoriesとmodelsで完結するのですが、複数のドメインが絡み合うロジックについてはservicesに定義します。(次回に続く?)