redux observableとgraphqlを組み合わせてみる

rxjsを触ってみたくて、redux observableとgraphql（apollo client）を使った簡単な画面を作りました。

ポケモンの名前でgif画像の検索ができます。
github
https://github.com/pokotyan/next-observable
デプロイ先
https://flamboyant-shaw-acfdd8.netlify.com/

<img width="856" alt="スクリーンショット 2018-09-23 20.17.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/131625/9fa9d0a7-948d-42c4-c9b7-4a069fc057f7.png">


# 利用した外部API、データ
https://qiita.com/seya/items/47dc0ebae55674d8902f
こちらで紹介されていたものを利用しました。具体的には以下の３つを利用しています。

https://github.com/lucasbento/graphql-pokemon
https://github.com/fanzeyi/Pokemon-DB
http://www.pokestadium.com/tools/sprites

# rxjs
まだ私も勉強中ですが、ざっくりいうとObservable(川)にストリーム(桃)を流して、rxjsのオペレータでその桃を切り刻んだり、なんやかんやしたりします。

redux observableだとactionの発火をトリガーに桃が流れ始めるイメージです。
あるactionの発火で桃が流れ始め、桃に対してドメインの処理を行い、また別のactionを返します。
これをredux observableではepicsと言うようです。
以下は、ポケモンの一覧データを取得するepicです。

```js
export const fetchPokemons = (action$) =>
  action$.pipe(
    ofType(pokemonActions.FETCH_POKEMONS), // 1)FETCH_POKEMONSが発火したら
    mergeMap(action => client.query({      // 2)graphqlのクエリを叩いて
      variables: {
        first: action.payload.first,
      },
      query: gql`
        query($first: Int!) {
          pokemons(first: $first) {
            id
            number
            name
            attacks {
              special {
                name
                type
                damage
              }
            }
            evolutions {
              id
              number
              name
              weight {
                minimum
                maximum
              }
              attacks {
                fast {
                  name
                  type
                  damage
                }
              }
            }
          }
        }
      `
    })),
    map(response => { // 3) graphqlのレスポンスに日本語のポケモン名を足して
      return response.data.pokemons.map(pokemon => {
        let jname;

        pokemonConfigList.some(pokemonConfig => {
          if (pokemonConfig.ename === pokemon.name) {
            jname = pokemonConfig.jname;
            return true;
          }
        })

        pokemon.jname = jname || '';

        return pokemon;
      })
    }),
    map(pokemons => { // 4) graphqlのレスポンスにgifのurlを足して
      return pokemons.map(pokemon => {

        const pokemonGifUrl = pokemon.name.toLowerCase()
          .replace(/\./g,'')
          .replace(/'/g,'')
          .replace(/\-/g, '')
          .replace(/\s/g, '-');

        pokemon.gif = `http://www.pokestadium.com/sprites/xy/${pokemonGifUrl}.gif`;

        return pokemon;
      })
    }),
    map(pokemons => pokemonActions.fetchPokemonsFulfilled(pokemons)) // 5) actionをdispatchする
  );
```

あるactionを受けて桃が流れ始め、最終的には別のactionが返されるという流れが基本となっているため、以下のように同じactionを返すepicを作ると無限ループが発生してしまします。

```js
// DO NOT DO THIS
const actionEpic = action$ => action$; // creates infinite loop
```
参考：https://redux-observable.js.org/docs/basics/Epics.html


# redux observableの便利に感じたところ
ボタンなどのクリックをトリガーにリクエストを投げる際、そのままだと、ボタン押下のたびにリクエストが走ります。
redux observableを使えば、ある一定間隔内に連続して投げられた処理は１回の処理として間引く。ということが簡単にできます。

```js

export const fetchPokemons = (action$) =>
  action$.pipe(
    ofType(pokemonActions.FETCH_POKEMON),
    debounceTime(500), // 500ミリ秒の間はFETCH_POKEMONが何度発火しようが、処理は１回にまとめられる
    // some code
  );
```

これ以外にも、前回と値が違う時のみ処理を通すなど、rxjsには色々なオペレータがあります。
フォームの入力に伴ういろんな処理のハンドリングに便利なものがrxjsには備わっているように感じました。

# redux observableとapollo clientの組み合わせ方
https://github.com/apollographql/apollo-client/issues/1842

通常apollo clientを使う場合、ApolloProviderを使ってgraphqlのクライアントを全体に流し込みますが、redux observableと組み合わせる場合、graphqlを利用したい場所で都度クライアントをimportしてね、っていう感じみたいです。


# rxjsの学習に使えるサイト
https://ninjinkun.hatenablog.com/entry/introrxja