Vue CLI3.0 , Vuex ,  Firestoreのお勉強メモ

# 背景
Web開発ではAngular/Firebaseばっかり使っていたので他のフレームワークを学習したかったのでVueの勉強してみた
Vue/Vuex/Firestoreについて勉強したので個人的考えをまとめたメモとして投稿
Typescriptのような型ありきのプログラムしか書いてなかったからどうしても型を使いたくなってしまう...

# 注意
Vue　/ Vuex / 　Firestoreの場合、vuexfireを使うことがよくあるが使っていない
https://github.com/posva/vuexfire

# 成果物
Chatアプリ
~~(自由に設定できるIDで人を判断するという本番ではあり得ない雑な構成)
※ Auth, sinIn/Out機能なし。気が向いたら実装予定~~
Auth Guard機能とSignIn機能を作成しました。
https://github.com/k-cafe/ChatSampleVue
![ezgif-4-1a02701c477c.gif](https://qiita-image-store.s3.amazonaws.com/0/307988/26317a21-8352-90ce-b38e-f418a13aa2d7.gif)

# フォルダ構成
```
src
|-- assets
|-- components    <- Routerに登録したMain Vue（親コンポーネント）
|-- environments  <- 設定ファイルを格納(gitignoreに指定しているので存在しない。今回はFirebaseの設定ファイルを格納)
|-- models
|-- repositories  <- FirestoreへのCRUD処理プログラム
|-- router
|-- store
|-- views         <- 子コンポーネント
|-- App.vue
|-- main.js
```

# 個人的考え
### 1. Firebaseの通信処理の部分とStoreの役割分けたい、というかプログラムソースを分けておきたい
- VuexのStoreはもともとデータの一元管理のためだけの機能と公式で読んだ   
    -> Firebaseとの通信処理も同じ部分に追加するのはなんか違う気がする   
    -> データ処理やデータ自体を管理するVuexのStoreにFirebaseの通信機能を搭載することは、   
       ちょっとニュアンスが違うかもしれないけど単一責任の原則に反してるんじゃ...   
    -> **上記のStoreとRepositoriesに分割しよ**


結果
- コールバック関数を使って分離
store/comment.js(一部抜粋)とrepositories/comment-repository.js

      // TODO: ここでCommentRepositoryを毎回生成するのは無駄なので修正の必要あり。
      this.commentRepository =  new CommentRepository();

      // callback function
      this.findAll = this.commentRepository.findAll((type, comment) => {
        if (type === 'added') { commit('add', comment) }
        else if (type === 'modified') { commit('set', comment) }
        else if (type === 'removed') { commit('remove', comment) }
      });
```
import db from './database';
import { Comment, User } from '../models'

export class CommentRepository {
  constructor() {
    this.commentsRef = db.collection('comments');
  }

  findAll(crudFunction) {
    return this.commentsRef.orderBy('date', 'asc').onSnapshot(querySnapshot => {
      querySnapshot.docChanges().forEach(change => {
        const comment = new Comment(
          change.doc.id,
          change.doc.data().message,
          new User(change.doc.data().user.id, change.doc.data().user.name),
          change.doc.data().date
        );
        crudFunction(change.type, comment);
      });
    });
  }

  add(comment) {
    this.commentsRef.add(Object.assign({}, comment));
  }

  remove(comment) {
    this.commentsRef.doc(comment.id).delete()
  }
}
```

### 2. Store内で管理しているList内のオブジェクトを更新してもUIの変更が走らない場合は更新したいオブジェクトをコピーして上書きする

```
class Comment {
  constructor(id, message, user, date) {
    this.id = id;
    this.message = message;
    this.user = user;
    this.date = date;
  }
}

class User {
  constructor(id, name) {
    this.id = id;
    this.name = name;
  }
}
```
上記のCommentオブジェクトをListとしてStoreで管理していて、Commentのmessageを修正した場合、
Storeに管理しているデータとしては変更されているが、UIで表示しているmessageが更新されない
ただしCommentがAddされた際はUIは更新される...
なのでStoreでデータ管理されているListは、オブジェクトをList化した場合オブジェクトのポインタのみを管理しているだけであってオブジェクトのプロパティは確認していない、できないという仮説を抱き、
Commentのmessageを編集するメソッドに**Object.assign({}, Comment)**を追加したら無事動いた！！！！
が、あくまで仮説なので誰か本当のことを教えてください（切実）


# 参考文献
- https://qiita.com/rubytomato@github/items/78087a2c69389f642760
- https://itnext.io/how-to-structure-a-vue-js-project-29e4ddc1aeeb