vue-cliで生成した状態でsrc
以下はこうなっています。(assetsは省略)
├── components // コンポーネント
├── views // ページと1:1
├── App.vue // トップページのコンポーネント
├── main.js // プラグインの使用など
├── router.js // ルーティング
└── store.js // Vuex
もちろんこのままゴリゴリ書いていくことも可能ですが、components
以下にロジックが大量にかかれ、共通化されてない見通しの悪いコードが生成されることになります。
コンテナコンポーネントを追加する
コンテナコンポーネントを入れるcontainers
を追加しました。
├── components // コンポーネント
├── containers // コンテナコンポーネント
├── views // ページと1:1
├── App.vue // トップページのコンポーネント
├── main.js // プラグインの使用など
├── router.js // ルーティング
└── store.js // Vuex
コンテナコンポーネントとは何でしょうか?
- Vuexを知っている
- 他のコンテナコンポーネントを呼び出してもよい
- ラッパーのdivを除いて独自のDOMマークアップは書かない
以下の記事がすごくわかりやすいのでぜひ一度読んでみてください。
2018年Vue.jsとVuexを使ってる人に提案するコンポーネントの分類と設計パターン - Qiita
コンテナコンポーネントにロジックを寄せることでcomponents
以下ではpropsで値を受け取るだけでよくなり、テストも書きやすくなります。
ですが、ロジックがcontainers
以下に移動しただけなので、次はcontainers
の見通しが悪くなりました。
ロジックの置き場所を考える必要がありますね。
componentsを整理する
ロジックの置き場所を考える前に、components
以下をpropsで受け取ったコンポーネントの書き方のポイントを紹介します。
- v-model
- emit or callback
v-modelは糖衣構文
v-modelと書くだけでテキストをリアクティブなデータを扱えるのはすごく便利なのですが、v-bind
、v-on
、v-model
とか最初の方は混乱しますよね。v-modelは糖衣構文なのでv-bind
とv-on
を使って書き換えることができます。(:
はv-bind、@
はv-onの省略記法)
<input v-model="text">
↓
<input :value="text" @input="text=$event.target.value">
emit or callback
どちらも子から親に変更を伝えることができます。(親からpropsで受け取った値は基本的に子側で変更できないので、変更を伝える必要があります。)
最初はemit
を使ってたのですが、Vue固有の書き方なので少しコードを書かないと使い方を忘れることがよくありました。callback
ならVueが初めての人も分かる書き方なので個人的にはコールバック方式をオススメします。
v-model
とemit or callback
を理解しておくことで、コンポーネントには一切の状態(data)を持つことなく、propsから値を受け取るだけのシンプルなコンポーネントになります。(ステートレスコンポーネント)
以下のItemList.vueは親から受け取ったfilter.userId
をv-modelで指定していますが、オブジェクトのプロパティなので子側でも書き換えができます。
API通信を分離する
現在はcontainers
でaxiosをimportしているので、テスト時にaxiosをモック化する必要があります。また、axios以外のライブラリを使うことになった場合など変更が容易ではありません。
以下の記事を参考にrepositories
を作成します。
【Vue.js】Web API通信のデザインパターン (個人的ベストプラクティス) - Qiita
今回はQiitaのAPIをコールするだけなので少し簡略化しています。また、axiosを知っているのはrepositories
以下のみにしたいのでAxiosPromiseを返さずPromiseを返しています。
src/repositories/qiitaRepository.ts
コンポーネントからAPIを呼ぶコードのテストではAxiosMockなどを使わずにqiitaRepositories
をsinonなどでstub化すればいいかと思います。
ここまでのディレクトリ構成
├── components // ステートフルコンポーネント、ステートレスコンポーネント
├── containers // コンテナコンポーネント
├── repositories // API通信
├── views // ページと1:1
├── App.vue // トップページのコンポーネント
├── main.js // プラグインの使用など
├── router.js // ルーティング
└── store.js // Vuex
今回はこれで終わりです。
次回はservicesとmodelsを追加したパターンを紹介したいです。