読者です 読者をやめる 読者になる 読者になる

tomoima525's blog

Androidとか技術とかその他気になったことを書いているブログ。世界の秘密はカレーの中にある!サンフランシスコから発信中。

ReactNativeに必要不可欠なReduxとMiddlewareのフローを理解する

f:id:tomoima525:20170424163521p:plain

最近ReactNativeをちょこちょこ書いています。アプリ向けのReactNativeを書くにあたって理解が不可欠になるのがデータフローの仕組みであるRedux、及び様々な処理を仲介するMiddlewareです。小さなアプリをつくってみて一通り把握したので、整理も兼ねて初めてReact-Reduxを触れる時にどの辺を見ればよいかまとめてみます。
作ったのはChuckNorris FactsのJokeを検索して表示するアプリです。

github.com

デモ動画

ざっくり仕様を述べると

  • ReactNative + Redux + RxJs
  • 検索ワードを投げる、ローディング、結果表示のステートをReduxで管理
  • https://api.chucknorris.io/APIをMiddlewareであるredux-observable経由で叩いて取得
  • APIレスポンスは RxJsでストリームをハンドル

という風になっています。

Reduxとは

すでにご存知な方も多いですが一応述べておくと、ステート管理のフレームワーク及びそれを実現するライブラリです。 ここで色々説明するよりRedux本家のページが分かりやすいです。
チュートリアルも充実しています。但しReactNativeではなくReactで書かれているため、自分のようにJavascript自体があまり馴染みが無い場合、ReactNativeとの違いに戸惑うこともあるかもしれません。

あとこちらのマンガでわかるReduxもおすすめです。

code-cartoons.com

Reduxの大まかな流れは以下になります。

(1) ReactコンポーネントからActionをコール
(2) ActionをStoreにあるReducerに渡す(dispatchと呼ばれる)
(3) Reducerがステートを更新してReactに返す(React側はコンテナを経由してコンポーネントにステートを渡す)

Reduxが優れているところ

上記の流れを見ると分かる通り、ステートで挙動が制御されるので、Atomic Design pattern である Reactと非常に相性が良いです。
React(ReactNative)はUIコンポーネントにすぎず、ある状態を渡すとそれを愚直に表示するだけのものです。その状態を綺麗に管理できるのがReduxになります。

余談ですが、ReduxのAPIリファレンスをみると登場するメソッドが6つしかないです。インタフェースよりも仕組みを理解することが重要なライブラリですね。

Middlewareとは

Reduxの非常に優れた仕様の一つで、ActionからReducerの間に発生する処理をつかさどる部分になります。上の流れで言うと(2)の部分で発生する処理をハンドルします。例えばAPIリクエストであったり、ログ処理を行ったりする部分です。
Middlewareの特徴としてはReduxを離れて様々なサードパーティのエクステンション等に処理を託すことができる点があります。サードパーティのMiddlewareとしてはredux-observable,redux-saga,redux-thunkなどそれぞれ色々な特徴を持ったものがあります。

ReactNative + Redux プロジェクトで見るべきところ

上記を踏まえた上で、ReactNativeのコードを追う場合に見るべきところは以下になるかなと思います。

トップのindex.js

ここではReducerとMiddlewareからStoreを生成し、アプリに設定するコードがあります。自分のアプリですと、index.anroid.js にあたります。

import chuckNorris from './js/reducers';
import chuckEpic from './js/epics';

// Middlewareを生成
const epicMiddleware = createEpicMiddleware(chuckEpic);
// Storeを生成 
const store = createStore(chuckNorris, applyMiddleware(epicMiddleware));

export default class ChuckNorrisViewer extends Component {
  render() {
    return (
      <Provider store={store}>// Appに設定
        <App/>
      </Provider>
    );
  }
}

Epics

Middlewareに託された各処理のことをEpicと呼びます。Epicsフォルダを見るとどのような処理がMiddlewareでハンドルされているかわかります。./js/epics/index.js を見ると

import { getNorris } from './posts';
const chuckEpic = combineEpics(getNorris);

と書かれていて、このアプリでは一つのEpicしか設定されてないとわかります。 さらにimportされた post.js を見てみると、

import {receivePosts} from '../actions'; //Action Creator
import {REQUEST_POSTS} from '../actions'; // Action Type
export const getNorris = action$ => {
  return action$.ofType(REQUEST_POSTS).mergeMap(action => {
    return ajax.getJSON(`https://api.chucknorris.io/jokes/search?query=${action.payload}`).map(response => receivePosts(response));
  });
};

ActionがREQUEST_POSTSであった場合にAPIリクエスト処理を行い、それを再度Action Creatorに返しているのがわかります。

Reducers

今度はReducersを見てみます。Reducersにはステートがどのように更新されているかが書かれています。./js/reducers/index.js を覗いてみると

const chuckNorris = combineReducers({
  searchResult,
  postByKey,
  visibilityFilter,
});

3つのReducerが登録されていることがわかります。例えばsearchResult.jsを見てみると

const searchResult = (state = {}, action) => {
  switch (action.type) {
    case RECEIVE_POSTS:
      return {
        ...state,
        items: action.payload
      };
  }
};

となっていて、RECEIVE_POSTS というActionを受け取った場合はpayload入れたステートを再度生成して返しているとわかります。なお ...stateObjectSpreadと呼ばれるSyntaxで、要は元のステートをコピーして新しいステートを生成しています。

Action

(2) ActionをStoreにあるReducerに渡す(dipatchと呼ばれる) の部分にあたります。どのようなActionがあるかというのも全体像を知る上で重要です。actions/index.jsを見てみると

export const RECEIVE_POSTS = 'RECEIVE_POSTS';
export const REQUEST_POSTS = 'REQUEST_POSTS';

//リクエストする時のAction
export const requestPosts = ( key ) => {
  return {
    type: REQUEST_POSTS,
    payload: key,
    isFetching: true,
  }
};

//結果を受け取った時のAction
export const receivePosts = ( response ) => {
  return {
    type: RECEIVE_POSTS,
    payload: response.result,
    isFetching: false,
  }
};

ActionTypes.jsとAction.jsを分ける場合もあるようですが、今回は同じファイルに書いています。 Actionにどのようなタイプがあり、それぞれのActionが取る値がわかるかと思います。

React Container

今度は各画面でどのようにReact側にステートが渡されて描画されるかを見ます。ContainerはReactにおいてどのように処理が行われるか(そして実際のUIコンポーネントに渡すか)を決めます。詳しくはここがわかりやすいです。
“どのように処理が行われるか” という言葉からも分かる通り、Reduxとも縁が深いところになります。

検索ワードを入力するContainerである containers/Input.js を見てみると

import { requestPosts } from '../actions';
...
const mapDispatchToProps = (dispatch) => {
  return {
    onButtonPress: bindActionCreators(requestPosts,dispatch),
  };
}
export default connect(null, mapDispatchToProps)(Input);

という処理があります。(1) ReactコンポーネントからActionをコールの部分で、これがActionを呼ぶ時のおまじないになっています。Storeに渡すdispatchにpropsで定義された値を接続しているわけです。ここでは onButtonPress という値が requestPosts をコールするようになります。
次に検索結果を表示するcontainers/ResultList.jsを見てみると、今度は

const mapStateToProps = (state) => {
  return {
    result: state.searchResult,
    visibilityFilter: state.visibilityFilter,
  }
}
export default connect(mapStateToProps)(ResultList);

という処理が見えます。これが(3) Reducerがステートを更新してReactに返すの部分で、Reducerから受け取ったステート更新をpropsに渡して描画を行うための手続きになります。ここでは searchResultvisibilityFilter という2つのReducerによるステートを受け取っています。

これでアプリ内の一通りの処理が追えたかと思います。

まとめ:Reduxをどう理解していけばよいか

自分にとってReduxの最初のつまづきははステートがどこから渡されて、どう処理されて更新していくのかが初見だと理解しにくい点でした。一度アプリを作ってconsoleにログを出しつつステートの変化を追うと、理解が深まったのでおすすめです。

バークレーってどんな街

自分はサンフランシスコから電車で40分程度のところにあるバークレー(Berkeley)というところに住んでいます。カリフォルニア大学バークレー校がある、いわゆる学園都市です。サンフランシスコに住んでいる人や日本から来た人からは大抵どんなところなの?と聞かれるので、ブログに書いておこうと思います。

どの辺にあるのか

f:id:tomoima525:20170409150153p:plain

バークレーイーストベイと呼ばれる地域にあります。サンフランシスコから電車(BARTと呼ばれる)でおよそ40分。車ならベイブリッジという橋を渡って、空いていれば市内まで25分です。 日本の関東で例えるなら、サンフランシスコが東京とすると、バークレーは総武線でつながっている千葉みたいな感じです。 途中、オークランドという街を経由します。ここは結構治安が悪いことで有名です。電車で通過するだけで「あ、よくないなー」ってわかるレベルです。

どんな街

園都市らしく、活気があり、自然も多いです。大学の玄関に面した街の中心部は若い人が多くて賑わっており、歩いているだけで元気になります。自分がこの街を選んだ理由のひとつです。

f:id:tomoima525:20170408151554j:plain:w400
大学通り

f:id:tomoima525:20170408152052j:plain:w400
カリフォルニア大学バークレー

f:id:tomoima525:20160213142818j:plain:w400f:id:tomoima525:20170409092431j:plain:w400
広大な土地を持っていて緑が多い

一方、中心部を北(オークランドと反対方向)に向かうと、ぐっと緑が多くなります。住んでいる人も年配の人が多いようです。

f:id:tomoima525:20170408143420j:plain:w400
一軒家が多い

f:id:tomoima525:20170408144225j:plain:w400
住宅街にとうとつに雰囲気のあるお店が出てきたりする

f:id:tomoima525:20170408150916j:plain:w400
ドッグパークもでかい

f:id:tomoima525:20170408150117j:plain:w400
自転車道も整ってる

中心部から徒歩30分位で海に出ます。ハーバーがあって気持ち良いです。 f:id:tomoima525:20160924144645j:plain:w400

住みやすいの

以下の点でとても住みやすいです。

もくもく出来るカフェが沢山

学生街らしく、カフェがいたるところにあり、しかもWifi、電源無料です。学生が夜遅くまで入り浸っています。そういえばPeet’s coffeeバークレーで創業してますね。 また学園都市だけあって生活に必要なお店、ものは大体揃っています。 個人的には映画館が駅前に3つ(ハリウッド映画専門と単館系)があるのがうれしいです。

自然が多い

サンフランシスコに比べて圧倒的に自然が多いです。穏やかな気分になります。ランニングする場所には事欠かないです。

オーガニック

バークレーはオーガニック発祥の地と言われていて、オーガニックな製品や食品が山ほどあります。Berkeley Bowlは地元で特に有名なお店です。オーガニックなキノコだけで10何種類もあります。ビーガン(完全菜食者)向けの料理店なども充実してます。 レストランもサンフランシスコ以上に評判の良いお店が沢山あり、目抜き通りのShuttackにあるレストランはGourmetGhettoと呼ばれています。

f:id:tomoima525:20170408151650j:plain:w400
オーガニック関係ないですけど、一風堂バークレーに店舗を近日中に開くらしいです。

困ることは

電車がよく遅延or止まる

BARTというほぼ唯一の公共交通機関(一応バスもあるけど)が劇的に弱い。風が吹いたり雨が降ったりするとだいたいどこかの駅で不具合が発生して止まります。更に言うと日曜日はサンフランシスコに向かう直通電車がなくなるので結構不便です。

サウスベイが遠い

いわゆるシリコンバレーと呼ばれるサウスベイの地域に行こうとすると、電車を乗り継いで2時間半-3時間はかかります。車があれば1時間程度なのですが。千葉から横浜まで行くイメージです。サウスベイ側に住んでいる知り合いが多いので、そっち方面に出かける時はなんとかならんかなと思います。

住むならサンフランシスコとどっちがよいかな

いわゆる都会的な生活をしたいならサンフランシスコですかね。落ち着いた雰囲気や学生的な活気を好むのであれば、バークレーはおすすめです。ちなみに家賃的な話で言うと感覚的にはサンフランシスコより10-20%位は安いんじゃないかと思います。あと消費税も数%安いです。

Android Payの実装話とかWebViewの話で発表してきた

先月日本に出張した際に potatotips #35 (iOS/Android開発Tips共有会)Shibuya.apk #11 にて発表してきました。

続きを読む

アメリカ大統領選挙の1日

4年に一度しかない特別な日ということで、色々な風景を撮ってみました。

投票所

投票所は主に教会や公共機関の様子。
f:id:tomoima525:20161108081433j:plain:w300

続きを読む

アニメの名言をSlackに引用できるkotoha-slackを作りました

Slack上でアニメの名言を引用したい時に、スラッシュコマンドで一覧を表示できるkotoha-slackを作りました。
f:id:tomoima525:20161016162915g:plain

コードはGithubにあります。
github.com

続きを読む

バックアップ機能がついたTwitCal 3.4.0をリリースしました

Android向けのカレンダー形式TwitterClient TwitCalの最新版をリリースしました。 今回はいつものバグ修正と合わせて、バックアップ機能を追加しました。

TwitCal Free ツイートをカレンダーでふりかえろう
TwitCal Free ツイートをカレンダーでふりかえろう
開発元:tomoima@kumonos
無料
posted with アプリーチ

広告無し、FavしたTweetも表示できるPro版はこちら

TwitCal Pro ツイートをカレンダーでふりかえろう
TwitCal Pro ツイートをカレンダーでふりかえろう
開発元:tomoima@kumonos
¥100
posted with アプリーチ

詳細については以下を御覧ください。

続きを読む

2年目以降のエンジニアなら手元に置いておくべき一冊 "スーパーエンジニアへの道"

f:id:tomoima525:20160907004837j:plain:w300

今日は表題にある一冊の本について紹介します。この本については、折々につけて人に話したりTwitterでつぶやいているのですが、いつも伝えきれないのでブログに書いておきます。

続きを読む