【Composition API】StoreパターンでVuexを使わずに状態管理をする

# はじめに
こんにちは。@chan_kakuです！今回は[Vue Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vue) 11日目の記事です。

みなさんComposition API使っていますか??今年のVue Advent CalendarはComposition APIの話がとても多いですね！
ここからみなさんがComposition APIに非常に関心があることがわかります。
今回は来たるVue 3.0で入るComposition APIをつかってVuexを使わずにStoreパターンを利用して簡易状態管理をしてみたいと思います！

## そもそもVuexって何？
今更ですが、初めてみたという方のために説明を入れておきます。
[Vuexの公式ドキュメント](https://vuex.vuejs.org/ja/)をみてると最初にこのように書いてあります
>Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリです。 これは予測可能な方法によってのみ状態の変異を行うというルールを保証し、アプリケーション内の全てのコンポーネントのための集中型のストアとして機能します。 また Vue 公式の開発ツール拡張と連携し、設定なしでタイムトラベルデバッグやステートのスナップショットのエクスポートやインポートのような高度な機能を提供します。

Vuexをよく使うパターンとしては、親子関係ではなく、兄弟関係のコンポーネント間で何かしらの状態を渡したいときなんかに使われます。
ただ、公式ドキュメントにはこのようにも書いてあります。
>Vuex は、共有状態の管理に役立ちますが、さらに概念やボイラープレートのコストがかかります。これは、短期的生産性と長期的生産性のトレードオフです。
もし、あなたが大規模な SPA を構築することなく、Vuex を導入した場合、冗長で恐ろしいと感じるかもしれません。そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。単純な ストアパターン が必要なだけかもしれません。しかし、中規模から大規模の SPA を構築する場合は、Vue コンポーネントの外の状態をどうやってうまく扱うか考える絶好の機会です。Vuex は自然な次のステップとなるでしょう。

つまり、公式的にはそこまで大きくないアプリケーションであるにもかかわらず、単に状態管理したいだけのために入れるのはナンセンスで、それなりの規模のアプリケーションで使うことをおすすめしています。

そこで公式ドキュメントに乗っている通りStoreパターンを利用して兄弟関係のコンポーネント同士で状態管理をしてみたいと思います。

# 早速Composition APIで状態管理してみる
## 作るもの
導入の前に今から作るもののイメージがあった方が作りやすいと思うので載せておきます
![gm3id-u8uch.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259982/e8d1339c-f913-f527-67cc-db2dbad0e604.gif)

このようにtext-boxに入力したテキストをsetボタンを押すことでstoreにセットされ、getボタンを押すことでstoreの状態を取得することができいます。

## 導入
まずはいつものごとくvue-cliを使ってプロジェクトを利用していきます

```shell
$ vue create adventCalendar
```
オプションはよしなに好きなものを選んでください

その後、Composition APIをVue 2.xでも利用できる [@vue/composition-api](https://github.com/vuejs/composition-api) を入れていきます

```shell
$ yarn add @vue/composition-api
```
その後先ほどvue-cliで作成したプロジェクトの`/src/main.js`に以下のように記述することでComposition APIを利用することができます。

```main.js
import Vue from 'vue'
import App from './App.vue'
import VueCompositionApi from '@vue/composition-api';// 追加した箇所

Vue.use(VueCompositionApi);// 追加した箇所

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

## 状態管理
ここからようやくStoreパターンを使った状態管理に入ります
storeパッケージを切って、その配下に`store.js`を作成します

```store.js
export let store = {
    state: {
        message: 'this is first message'
    },
    getMessage() {
        return this.state.message
    },
    setMessage(newVal) {
        this.state.message = newVal
    }
}
```

続いて、component側を触っていきます
`/src/components/HelloWorld.vue`を以下のように修正していきます

```HelloWorld.vue
<template>
  <div>
    <textarea cols="30" rows="10" v-model="state.privateMessage"></textarea>
    <p>グローバルメッセージ:{{state.globalMessage}}</p>
    <button @click="setMessage">set</button>
    <button @click="getMessage">get</button>
  </div>
</template>


<script>
import { reactive, onMounted } from '@vue/composition-api'
import { store } from '@/store/store.js'

export default {
  name: 'HelloWorld',
  setup() {
    onMounted(() => {
      getMessage()
    })

    const state = reactive({
      privateMessage: '',
      globalMessage: ''
    })

    function getMessage() {
      state.globalMessage = store.getMessage()
    }

    function setMessage() {
      store.setMessage(state.privateMessage)
    }

    return {
      state,
      getMessage,
      setMessage
    }
  }
}
</script>
```

Composition APIは基本的に`setUp()`内で使っていくことになります。
`onMounted`はVue 2.xまでのライフサイクルであるmountedと同じものになります。他にもいままで同じようにライフサイクルをフックすることができますが一部使えなくなっているものがありますのでご注意ください。
`reactive`はVue 2.6で追加された`Vue.observable()` と同じものでオブジェクトをリアクティブにしてくれるAPIです。
コンポーネント側ではこのようにstoreの状態(state)のgetter/setterを利用して状態を取得/変更していきます。
template側で利用したいオブジェクト、関数等がある場合はreturnで返してあげることで利用することができます。
ここまでみていただたとおり、従来の書き方で連発していた`this`がなくなっています。
初めて使ったとき個人的にはこれだけでもかなり嬉しく感じました。

今回は兄弟コンポーネントでの状態共有をしていきたいので、兄弟コンポーネントを作っていきます。
今回はサンプルなので、`HelloWorld.vue`をコピーした`HelloWorld2.vue`を作成し、`App.vue`でimportするようにしました

これで完成です！！

# 感想
ちょっとしたアプリケーションで状態管理をしたいだけの場合、このようにStoreパターンを利用することで状態管理をすることができました。
Vuexを使うかどうかの判断は難しいですが、個人的な意見としては、いらないものはできるだけ省きたいのでまずはStoreパターンでやってみる等でいいのかなと思ってます。
Composition APIの方は今回の例ではあまり旨味を出せていませんが、もう少し複雑なものになってくると、やりたいこと単位で分けてかけるので、レビューとかでもみやすくなってとてもいい感じだと思ってます！！
みなさんもVue 3.0がくる前にComposition APIにチャレンジしてみましょう！！

# その他
Composition APIの書き方にまだ慣れていないため、もっとこうした方がいい等の意見がありましたらコメントいただけると助かります。

# 参考
- [Vuex公式ドキュメント](https://vuex.vuejs.org/ja/)
- [Storeパターンについて](https://jp.vuejs.org/v2/guide/state-management.html#%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AA%E7%8A%B6%E6%85%8B%E7%AE%A1%E7%90%86%E3%82%92%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8B)
- [Composition API](https://vue-composition-api-rfc.netlify.com/api.html#setup)