Help us understand the problem. What is going on with this article?

Vue.js(v2.x.)を使ってメモアプリを作ってみた

More than 3 years have passed since last update.

この記事は、Vue.js Advent Calender 2016 5日目の記事です。

Vue.jsを使って、メモアプリを作ってみました。

* この記事では、説明のためのサンプルコードを書いていますが、Githubにあるコードとは似て異なります。ご注意ください。

screen-shot.jpg

環境

vue-router、vuex、Firebase を使っています。
vuefire はあえて使用していません。
vuex から Firebase を呼び出しています。

画面遷移

vue-router を使い、3つの画面を管理しています。
- Index(タイムライン)
- Viewer(ひとつのメモを見る)
- Editor(メモを追加、編集)
それぞれ、URLが個別に割り当てられるのがポイントです。

var router = new VueRouter({
  routes: [
    {
      path: '/',
      name: 'index',
      component: Index
    }, {
      path: '/editor',
      name: 'newEditor',
      component: Editor
    }, {
      path: '/editor/:id',
      name: 'updateEditor',
      component: Editor
    }, {
      path: '/viewer/:id',
      name: 'viewer',
      component: Viewer
    }
  ]
})

状態管理

vuex を使い、全コンポーネントから利用できるデータを管理しています。
Backend API にあたる部分が Firebase になっています。

vuex.png

Vue Component から vuex の state を取得

mapGettersを使ってStateを取得する例
computed: mapGetters(['user', 'currentUserName'])

vuex で保持する state を Component 内で直接変更することはできませんので、取得したデータを Component 内で変更するとエラーになります。

ダメな例
<input v-model="currentUserName">

その代わりに、次のように、書く事ができます。

良い例
<input :value="currentUserName" @input="something">

Vue Component から Vuex の Action を呼ぶ

他にmethodがない場合の例
methods: mapActions(['fetchMemos', 'signIn', 'signOut'])

signIntemplate 内で <p click="signIn">signIn</p> のように呼び出せます。

他にmethodがある場合&Component内のmethodからactionをdispatchする例
methods: {
  ...mapActions(['fetchMemos']),
  addCount () {
    this.count++
  },
  submit () {
    this.$store.dispatch('setUserInfo') 
  }
}

mapActions で Vuex に書いた Actions を取得できます。

Vuex

  • Action を呼び出すのが Dispatch
  • Mutation を呼び出すのが Commit
  • Mutation では同期処理のみ
  • Component から Vuex の State を 呼び出すのが Getter
  • Firebase は Backend API として Actions から呼び出すのを基本にした
  • Firebase のログイン状態監視の部分だけ、 Backend API が (Vue, Vuex) に依存する

Firebase

  • rule を決めるだけで良い。便利
  • vuex とのやりとりは、全て Promise にした
  • サーバーサイドのコード1つも書かずにできた
database-rules.jsonの一部
{
  "rules": {
    ".read": true,
    "users": {
      "$uid": {
        ".write": "auth !== null && auth.uid === $uid",
        "name": {
          ".validate": "newData.isString() && 2 <= newData.val().length && newData.val().length <= 100"
        }
      }
    },
    "memos": {
      "$uid": {
        ".write": "auth !== null && auth.uid === $uid",
        "$mid": {
          "title": {
            ".validate": "newData.isString() && newData.val().length <= 200"
          }
        }
      }
    },
    "publicMemos": {
      "$mid": {
        ".write": "root.child('memos/' + auth.uid ).hasChild($mid)",
        "title": {
          ".validate": "newData.isString() && newData.val().length <= 200"
        },
        "author": {
          "uid": {
            ".validate": "newData.val() == auth.uid"
          },
          "name": {
            ".validate": "newData.isString() && 2 <= newData.val().length && newData.val().length <= 100"
          }
        }
      }
    }
  }
}

大きく分けて、3つのツリーがあります。

  • users(ユーザーの名前を管理、ログイン管理は、Firebaseが自動でやってくれます)
  • memos(ユーザー個別ID別にメモを管理)
  • publicMemos(全てのメモを一元管理)

memos と publicMemos には同じデータが入っています。
memos には個別ユーザーID毎にツリーがあり、その下に各ユーザーのメモを格納します。
publicMemos には、全てのメモがズラーっと入っています。
memos に存在するメモしか、publicMemosには書き込みができないよう権限の設定をしました。
そのため、書き込み・削除の順番を意識する必要があります。
全てのツリーはログインしていないと書き込みができません。

Firebase と vuex の共存について

VueFire - Firebase meets Vue.js

Evan氏が2016年4月13日に書いている Firebaseブログです。
Vuex と Firebase の 統合について Vue.jsチームは調査中とあります。
Githubで、vuefire、vuexfire、vuex、Firebase 関連のサンプルを探したものの、「これは良さそう」というレポジトリはありませんでした。そのため、今回 vuefire はあえて使用せずに、vuex の Backend API の 部分に Firebase を配置しました。

vuefire の良いとこどりをした構造を考えて、今回のようなアプリに組み込めたら良いんですが、いずれにせよ大規模になると複雑になりそうです。vuefire と vuex の2つで状態管理をしたら良いのかな。。

参考

今回、この記事を書くにあたり、いくつかのレポジトリや記事を参考にさせていただきましたので、ご紹介させて頂きます!感謝!

Tech Blog Vue.js + Vuexで開発をしてみよう!

vuexを理解するのに参考になりました。

【意訳】Webpackの混乱ポイント

webpackの理解が深まりました。

Firebase Web Codelab

Friendly Chat というアプリ制作を通して、 Firebase の使い方を学ぶ事ができる公式サービスです。
60分で、Firebase を Web で使うための基礎を学ぶ事ができます。

vue-cli

ここにある Webpack のテンプレートをベースに、今回作成した Vue-memo の構造を考えました。
Vue-memo は、vue-cli にあるテンプレート webpackwebpack-simple の中間くらいの規模です。

vue-boilerplate

vuex と vue-router の共存させる書き方の参考になりました。

vuex

vuex のレポジトリにあるサンプルコードを何回も読みました。
できる限りここのサンプルから構造を真似して、自分でロジックを勝手に作らないように意識しました。

vue-hackernews-2.0

Vue.js 関連のサンプルコードの中で、最も参考にするべきレポジトリではないでしょうか。
しかし、私にはサーバーサイドレンダリングなど、理解が追いついておらず。。
いつかはサンプルコードを全て理解したい。そんなレポジトリです。

作ってみて感じた事

  • Webpack (もしくは、 Browserify)を使いこなすのが難しい
  • babel の理解が必要(ES2015, stage-2など)
  • webpack-dev-server の hot-reload は開発が捗る
  • Vue.js で、作ってみた系の記事・レポジトリが少ない(見つけられないだけかも。。)
  • ベストプラクティスを探すより、プロジェクトに合うアーキテクチャをチームで考えるのが良さそう

babel の presets で stage-2 を入れないと、spread演算子...を使えない。

babel の presets を設定します。

webpack.config.js
  babel: {
    presets: ['es2015', 'stage-2'],
  }

これで、次のような書き方が可能になります。

VueComponent内のコード例
...mapGetters(['currentMemo', 'currentMemoID'])

このコード、Github にある Vue.js 関連の サンプルによく出てきます。

ちなみに、

今回制作した Vue-memo は1年前(2015/12/13)に書いた記事「Vue.jsを使って、簡易メモアプリを作る。facebookログイン機能付き。」Vue.js v2.x. に対応させるという目標のもと、結局全て作り変えたたものです。

最後に

プルリクエスト大歓迎です。

日本語Vue.jsメンバーの皆様にはこの場をお借りして、いつも素晴らしい情報を発信してくださっているお礼を申し上げます。本当にありがとうございます。

明日は@mediba-kanamoriさんです。

akifo
フリーランスの JavaScript エンジニアです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした