vuexなし縛り。vueとapollo-link-stateでカウンター作成

# こんな感じになります

![ima
ge.png](https://qiita-image-store.s3.amazonaws.com/0/96277/6482c188-aa94-1dd7-cd8d-eff149a014ce.png)

**追記2018/12/13**
[Nuxt.js版ライブデモ on Netlify](https://condescending-perlman-13e781.netlify.com/)を稼働。

# ポイント

- vuexは使わない
- 代わり、[apollo-link-state](https://www.apollographql.com/docs/link/links/state.html)と、vueからapolloを使いやすくする[vue-apollo](https://github.com/Akryum/vue-apollo)を使う
- `withClientState`を使ってLinkを作る
  - `defaults`にフィールド`countSample`、最初の値`0`を入れる
  - `resolvers`にカウンタの値を増加させる`mutation`を作る
- コンポーネントからは`$`のついていない[`apollo`というフィールド](https://akryum.github.io/vue-apollo/api/smart-query.html#options)で、どの変数に値を入れるかを設定する
  - `mutation`を`this.$apollo.mutate`で呼び出す

# Linkを作る

- `stateLink`という、普通のGraphQLのlinkとは違うLinkを作成します

```main.ts
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'
import { withClientState } from 'apollo-link-state';
import { readCache, writeCache } from './apollo-link-state-store'

Vue.use(VueApollo)

const stateLink = withClientState({
  cache: new InMemoryCache(),
  defaults: {
    countSample: 0
  },
  resolvers: {
    Mutation: {
      increment: (obj: any, args: any, {cache}: any) => {
        var rtn = readCache(cache, "countSample")
        writeCache(cache, "countSample", rtn + 1)
        return null
      },
    },
  },
});

const apolloProvider = new VueApollo({
  defaultClient: new ApolloClient({
    link: stateLink,
    cache: new InMemoryCache(),
    connectToDevTools: true

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

# こうして関数化しておくと楽（GraphQLお作法の隠蔽）

- `apollo-link-state`は癖が強いので、自分で簡単関数`apollo-link-state-store`を作りました。

```apollo-link-state-store.ts
import gql from 'graphql-tag'

const argRead = (key: string) => gql`{ ${key} @client}`

const argReadCache = (key: string) => {
    return { query: argRead(key)}
}

const argWriteCache = (key:string, value: any) => {
    return {data: { [key]: value }}
}

//これをmain.tsから呼ぶ
export const readCache = (cache: any, key:string) => {
    return cache.readQuery(argReadCache(key))[key]
}

//これをmain.tsから呼ぶ
export const writeCache = (cache: any, key: string, value: any) => {
    return cache.writeData(argWriteCache(key, value))
}

//これをコンポーネントから呼ぶ
export const argMutate = (mutation: string) => {
    return {
        mutation: gql`mutation { ${mutation} @client }`
    }
}

//これをコンポーネントから呼ぶ
export const apolloState = (key: string) => {
    return {
        query: argRead(key),
        loadingKey: 'loading'
    }
}
```

# そしてコンポーネントからはこう呼ぶ

```vue
<template>
  <div>
    <div> {{ countSample }} </div>
    <v-btn color="success" v-on:click="increment()" > +1 </v-btn>
  </div>
</template>

<script>
import { apolloState, argMutate } from '../apollo-link-state-store'

  export default {
    apollo: {
      countSample: apolloState("countSample")
    },
    data () {
      return {
        countSample: 0
      }
    },
    methods: {
      increment() {
        this.$apollo.mutate(argMutate("increment"))
      }
    },

  }
</script>
```

# まとめ

- 癖が強いapollo-link-stateの作法を、半分くらい関数化して隠蔽する`apollo-link-state-store.ts`を作った。
- Vuexなくてもストアは作れる
- ただ、それが本当に嬉しいのかは人によるかな
- apollo-link-stateを使うことで、reduxやvuexに縛られない、フレームワークをまたぐようなストアもできそうな気がする。そういうのってマイクロフロントエンドとして必要にならないだろうか。FiNCなどの先人を切っている方がそういうストアをどうしているのかが気になる。

# おまけ

[この記事](https://qiita.com/kokorau/items/cbd96b2e9a77ae541216)と[こちら](https://qiita.com/_neekoko/items/aaedba104bb4997ab976)と[こちら](https://qiita.com/takanorip/items/d1e8618800d951780f4b)を参照しながら、

- Nuxt.jsで簡単なサンプルプログラム作成
- 今回のapollo-link-stateカウンターを移植

ができました。
ソースコードはこちら。

https://github.com/onelittlenightmusic/nuxt-apollo-link-state-counter

そしてNetlify上の[ライブデモ](https://condescending-perlman-13e781.netlify.com/)です。

ご査収ください