React Nativeによるモバイルアプリ開発はじめの一歩  〜プロジェクト作成・基本・Redux導入・画面遷移・サーバーとの通信〜


React Native は、Reactを用いたモバイルアプリ実装のためのフレームワークです。

特徴としては

1. 基本的には１ソースでiOS、Android両方のアプリを作ることができる(異なるところは分けて書くことも可能)
2. プログラミング言語はECMAScript2015。
3. ビュー部分のライブラリはReact.jsであり、JSXというHTMLっぽいタグで記述する。
4. 状態が変化すると表示にインタラクティブに反映される。

などがあります。

ここでの手順はMacOSXでHomebrewがインストール済みであると仮定しています。
Homebrewが入ってない方は、[Homebrewインストール手順](http://qiita.com/rabbit1013/items/1494cf345ff172c3b9cd)を参考に入れておいてください。
WindowsやLinuxは適当に... Linuxならnode入れたらあとは同じだろうけど、Windowsはわかりません。。

## nodeとcreate-react-nativeのインストール

```
$ brew install node
$ brew install watchman
```

なお、これを書いている2017年9月時点で、npm5ではcreate-react-nativeは動作しません。すでにnpm5をいれちゃってる場合は以下のようにして4系を入れる必要があります。

```
$ sudo npm install -g npm@4.6.1
$ sudo npm install -g create-react-native-app
```

## プロジェクトの新規作成

プロジェクト名を `MobileTimeline` として新しくプロジェクトを作ります。

```
$ create-react-native-app MobileTimeline
$ cd MobileTimeline
```

結構かかります。コーヒーでも飲みながら待ちましょう☕️

## 依存ライブラリのインストール

あとで使うのでReduxを入れておきます。

```
$ npm install --save redux react-redux
```

あ、それと型チェックライブラリの prop-types も。

```
$ npm install --save prop-types
```

画面遷移で使うナビゲーションライブラリ

```
$ npm install --save react-navigation
```

そしてHTTP APIを叩くためのライブラリ

```
$ npm install --save react-fetch
```

## 起動

とりあえず起動します。

```
$ npm start
```

が、エラーがでました
（ただし、このエラーが出た時は `watchman` 入れてなかったので、入れてたらエラーでないかも）

```
> MobileTimeline@0.1.0 start /Users/shin/src/react-learn/native/MobileTimeline
> react-native-scripts start

0:10:30: Unable to start server
See https://git.io/v5vcn for more information, either install watchman or run the following snippet:
  sudo sysctl -w kern.maxfiles=5242880
  sudo sysctl -w kern.maxfilesperproc=524288
```

とりあえず言われた通りに

```
$ sudo sysctl -w kern.maxfiles=5242880
```

もう一回起動

```
$ npm start
```

お、こんなんでました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/5f27a0a6-d253-a846-9a72-79166f6de4af.png" height=400px />

なにやら `Expo` というアプリをインストールしろと言ってくるので、iPhoneで [http://expo.io](http://expo.io)にアクセスしてインストールします。
(Androidはあとで調査)

Expoをインストールしたら起動して、 `Scan QR code` をタップ。表示されたQRコードを読み込むと自動的にアプリが起動します。この時、iPhoneとパソコンがネットワークを介して接続可能であることが必要です。
なお、アプリ画面から再度Expoの画面に戻るにはiPhoneを振ってシェイクします。


## プロジェクト生成直後のApp.js

`src/App.js` を開いてみるとこんな感じでした。
![スクリーンショット 2017-09-08 0.30.13.png](https://qiita-image-store.s3.amazonaws.com/0/13835/d5b1bde2-441f-c863-50c5-5dd27e9fe752.png "スクリーンショット 2017-09-08 0.30.13.png")


## ボタンの配置

ここでボタンを配置して、ボタンを押したらアラートが表示されるというシンプルな機能を実装します。
変更するのは `App.js` のみです。

まず、新たに `Button` `Alert` という２つのコンポーネントを使うので、これらをimportし、 `<View>` タグ内にボタンを配置します。
また、 `onPress` でイベント発生時に実行するメソッドを指定しておき、そこにアラートを出す処理を記述します。

```App.js
import React from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Open up App.js to start working on your app!</Text>
        <Text>Changes you make will automatically reload.</Text>
        <Text>Shake your phone to open the developer menu.</Text>

        <Button title="こんにちわ世界" onPress={this._handlePress} />
      </View>
    );
  }

  _handlePress() {
    Alert.alert("こんにちは！！");
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

これで次のようなアプリが動きます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/aea500e0-1d62-37f2-e204-3831229b6c60.png" height=400 />

<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/94dddfa8-a40b-3bcf-0772-f1a110071279.png" height=400 />

## stateによる値の保持

続いて、 `state` を使って値を保持するサンプルです。
以下のようにApp.jsを修正します。 テキスト入力エリアに文字を入力すると、その文字をリアルタイムにボタンのラベルに反映し、さらにボタンがタップされた時にその文字をアラートとして表示します。

```javascript:App.js
import React from 'react';
import { StyleSheet, Text, View, Button, Alert , TextInput} from 'react-native';

export default class App extends React.Component {
  constructor(props) {
      super(props);
      this.state = {hello: "こんにちは"}
  }

  render() {
    return (
      <View style={styles.container}>

        <TextInput
          style={{height: 40, width:300, borderColor: 'gray', borderWidth: 1}}
          onChangeText={(text) => this.setState({hello: text})}
          value={ this.state.hello } />

        <Button title={ this.state.hello }
                onPress={ this._handlePress.bind(this) } />

      </View>
    );
  }

  /* ボタンをクリックされたら現在の state.helloの内容をアラートする。 */
  _handlePress(e) {
    Alert.alert(this.state.hello);
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

## コンポーネントの分割
先ほどのアプリは、ビューの内容を全て `App.js` 内に書いています。しかし大きなアプリになると一定の塊ごとに分割することがあるでしょう。
ここでは `App.js` からテキスト入力エリア、ボタンを、別の `Hello.js` へ分割します。

まずは `App.js` を編集。

```javascript:App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Hello from './Hello.js';

class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Hello />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default App;
```

App.jsではテキストエリアやボタンの配置はせず、単に `Helloコンポーネント` を呼んでるだけです。
そして、もともと `App.js` にあった内容を `Hello.js` へ移します。

```javascript:Hello.js
import React from 'react';
import { View, Button, Alert , TextInput} from 'react-native';

class Hello extends React.Component {
  constructor(props) {
      super(props);
      this.state = {hello: "こんにちは"}
  }

  render() {
    return (
      <View>
        <TextInput
          style={{height: 40, width:300, borderColor: 'gray', borderWidth: 1}}
          onChangeText={(text) => this.setState({hello: text})}
          value={ this.state.hello } />

          <Button title={ this.state.hello }
                onPress={ this._handlePress.bind(this) } />
      </View>
    );
  }

  /* ボタンをクリックされたら現在の state.helloの内容をアラートする。 */
  _handlePress(e) {
    Alert.alert(this.state.hello);
  }
}

export default Hello;
```

## Reduxの導入
これまでは、それぞれのコンポーネントに `state` をもたせて、 `this.setState()` として保持している値を更新したりしてきましたが、ここでFluxの考え方を導入します。

Fluxの考え方については私がごちゃごちゃいうより解りやすい記事があるのでそちらを参照してください。
[Fluxとはなんなのか](http://qiita.com/knhr__/items/5fec7571dab80e2dcd92)

Flux自体は考え方なのですが、このFluxの考え方をもとに作られた[Redux]()というフレームワーク(?)があるので、これを使います。
[結局FluxやらReduxやらって何なのか個人的なまとめ](http://qiita.com/syossan27/items/7e1b2e07ac68b96bdaa7)

### reducer.jsの新規作成

まずはReducerを作ります。ファイル名は `reducer.js` です。
Reducerでは、　`state` と `action` を受け取る `reducer(state, action)` という関数を定義し、他のソースからも参照できるように `export` しています。
ここでは `action.type` の値を元に処理を分岐しています。 `action.type` には、このあと作る `action.js` で生成するアクションのオブジェクトで、必ず `type` プロパティだけは定義することになっていて、そこで `type` プロパティに設定した値によって `reducer.js` で処理が分かれるってことになります。
なので、処理内容を増やすにはここでswitch文に新たなcaseを増やすことになります。

```js:reducer.js
const initialState = {
  hello: "Hello World"
}

export default function reducer(state = initialState, action) {
  switch(action.type) {

    /* hello文字列を変更する */
    case 'HELLO_WORLD':
      return {
        ...state,
        hello: action.hello
      };

    default:
      return state
  }
}
```

### action.jsの新規作成

続いてAction Createrを実装します。ファイル名は `action.js` です。
ここでは `updateHello` という関数を定義し、 `dispatch(action)` 関数にオブジェクトを渡します。このオブジェクトは上で書いたように、typeプロパティだけは必須、残りの項目は任意で定義します。
ここでdispatchに渡したオブジェクトが先ほどのreducer関数でactionとして渡されます。

```javascript:action.js
export function mapStateToProps(state) {
  return state;
}

export function mapDispatchToProps(dispatch) {
  return {
    /* hello文字列を変更する */
    updateHello: (text) => {
      dispatch( {type: 'HELLO_WORLD', hello: text} );
    }
  }
}
```

### storeの生成

`App.js` において、 状態を管理する `store` を生成し、 `Provider` に渡す処理を追加します。
ポイントになるのは

1. 冒頭で `createStore` と `Provider` をimportしている点。
2. `const store = createStore(reducer);` でstoreを生成している点。
3. `render()` 関数内で、 `<Provier store={ store }>...</Provider>` として大きく `Provider` タグで囲って `store` を渡している点。

の３つです。

```js:App.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Hello from './Hello.js';
import reducer from './reducer.js';

const store = createStore(reducer);

class App extends React.Component {
  render() {
    return (
      <Provider store={ store }>
        <View style={styles.container}>
          <Hello />
        </View>
      </Provider>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default App;
```

### connectによるReactNativeとReduxの接続

最後に、Reduxによって管理されたstateの状態を参照したり変更したりするコンポーネントにおいて、ReactNativeとReduxを接続します。
また、これまでコンポーネント内で定義した `state` を使っていた部分を新たにReduxによって保持されているstateを使うように変更します。
修正後のソースが以下です。

```Hello.js
import React from 'react';
import { View, Button, Alert , TextInput} from 'react-native';
import { connect } from 'react-redux';
import {mapStateToProps, mapDispatchToProps} from './action.js';

class Hello extends React.Component {
  render() {
    return (
      <View>
        <TextInput
          style={{height: 40, width:300, borderColor: 'gray', borderWidth: 1}}
          onChangeText={ (text) => this.props.updateHello(text) }
          value={ this.props.hello } />

          <Button title={ this.props.hello }
                onPress={ this._handlePress.bind(this) } />
      </View>
    );
  }

  /* ボタンをクリックされたら現在の state.helloの内容をアラートする。 */
  _handlePress(e) {
    Alert.alert(this.props.hello);
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Hello);
```

最後の行で、これまでは `export default Hello;` だったところが、 `export default connect(mapStateToProps, mapDispatchToProps)(Hello);` となって、 `action.js` で定義した関数と関連づけられている点に注意してください。

### 動作確認

起動してテキストを編集するとリアルタイムにボタンのラベルに反映されています。

<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/84e5e420-ae8e-8d19-33c5-c8f7f78e8973.png" height=400>

また、ボタンをタップすると、現在の `state.hello` の内容でアラートが表示されます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/7dc6bc8b-8526-bcff-c044-5237af015c2f.png" height=400>

## 画面遷移

今やほとんどのアプリで画面遷移は必須です。なので、ReactNativeとReduxでアプリを実装している場合の画面遷移を導入してみます。

先にどんな機能を実装するのか確認します。

トップ画面は下の通り。 `Hello` と `Check` という２つのボタンが表示されるのみです。
このトップ画面はタイトルが `ホーム` と表示されています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/92efa81c-f59d-ef5c-c02a-29366fc750c4.png"  height=400 />


トップ画面で `Hello` をタップすると、iOSアプリの場合は画面が右に遷移して以下のような画面が表示されます。
これは、これまでのところで実装して来た `Hello` コンポーネントに他なりません。
テキストエリアで文字列を編集すると、リアルタイムにボタンのラベルが同じ文字列に変わります。
そして左上に `ホーム` というボタンが表示され、これをタップすると先ほどのトップ画面に戻ります。
<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/b086b827-e438-c8a7-daab-1bdd0bf3564b.png" height=400 />


今度はトップ画面で `Check` をタップすると、また画面が右に遷移して、 `チェック画面` というタイトルの画面が表示されます。
ここで画面中央にテキストで表示されるのは、先ほどの `Hello` コンポーネントの画面でテキストエリアに入力した文字列です。
<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/ea614bc7-9536-38f7-da5c-42649a762177.png" height=400 />

### App.jsの編集
ひとつづつ見ていきます。まずは `App.js` ですが、これは以下のようなソースになります。
ポイントとしては、
 
1. `stackNavigator` によってナビゲーターを作っているところ
2. そのナビゲーターを `App` コンポーネントの `render(){...}` でタグとして使用しているところ
3. そしてコンポーネントのタグ全体を `<Provider stor={ store }>...</Provider>` で包んで、Reduxのstoreで管理されている状態へのアクセスをアプリ全体で可能にしている点

の３点です。


```javascript:App.js
import React from 'react';
import { View } from 'react-native';
import { StackNavigator, addNavigationHelpers } from 'react-navigation';
import { Provider } from 'react-redux';

import { store } from './store.js';
import { styles } from './styles.js';
import Hello from './Hello.js';
import CheckScreen from './CheckScreen.js';
import HomeScreen from './HomeScreen.js';

const AppNavigator = StackNavigator({
  Home: {screen: HomeScreen},
  Hello: {screen: Hello},
  Check: {screen: CheckScreen}
});

class App extends React.Component {
  render() {
    return (
      <Provider store={ store }>
        <AppNavigator />
      </Provider>
    )
  }
}

export default App;
```

### sotre.jsの新規作成
先ほどまでは `App.js` 内でstoreを作っていましたが、ちょっと分かりにくくなって来たのでこれを外に出します。
ファイル名は `store.js` です。
 
```javascript:store.js
import { createStore } from 'redux';
import reducer from './reducer.js';

export const store = createStore(reducer);
```

### styles.jsの新規作成

store.js同様に、stylesも `App.js` から外に出してimportするようにリファクタリングします。

```javascript:styles.js
import { StyleSheet } from 'react-native';

export const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

### HomeScreen.jsの新規作成

先ほどの修正によって、 `App.js` はナビゲーションを呼び出すだけとなりましたので、これまで `App.js` 内にあったビューの部分を新たに `HomeScreen.js` というファイルに移します。

これまでのコンポーネントと異なる点は、 `static navigationOptions = {...}` としてナビゲーションで使用するオプション項目を設定している点です。ここで `title: "ホーム"` としているので、実際の画面のタイトルが `ホーム` となっているのです。

```javascript:HomeScreen.js
import React from 'react';
import { View, Button } from 'react-native';
import { styles } from './styles.js';

class HomeScreen extends React.Component {
  static navigationOptions = {
    title: "ホーム"
  }

  render() {
    const { navigate } = this.props.navigation;

    return (
      <View style={styles.container}>
        <Button title="Hello" onPress={ () => navigate('Hello') } />
        <Button title="Check" onPress={ () => navigate('Check') } />
      </View>
    );
  }
}

export default HomeScreen;
```

### Hello.jsの編集

Hello.jsは基本的にはそのままでいいのですが、一部修正します。

ひとつめは、先ほどの `HomeScreen.js` と同様に、ナビゲーションのオプションとしてタイトルを設定しているところ。

もう一つは、これまではやっていませんでしたが、 `PropTypes` による型チェックを導入しているところです。
これによって、 `Hello` コンポーネントに渡される `props` には、 `hello` というプロパティが含まれており、その値は文字列でなければならないという制約ができます。
型がちがっていたなどの場合は、実行画面で画面下に警告が表示されます。

```javascript:Hello.js
import React from 'react';
import { View, Button, Alert , TextInput} from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { mapStateToProps, mapDispatchToProps } from './action.js';
import { styles } from './styles.js';

class Hello extends React.Component {
  static navigationOptions = {
    title: "ハローワールド"
  }

  render() {
    return (
      <View style={styles.container}>
        <TextInput
          style={{height: 40, width:300, borderColor: 'gray', borderWidth: 1}}
          onChangeText={ (text) => this.props.updateHello(text) }
          value={ this.props.hello } />

        <Button title={ this.props.hello }
                onPress={ this._handlePress.bind(this) } />
      </View>
    );
  }

  /* ボタンをクリックされたら現在の state.helloの内容をアラートする。 */
  _handlePress(e) {
    Alert.alert(this.props.hello);
  }
}

/* 型チェック */
Hello.propTypes = {
  hello: PropTypes.string.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(Hello);
```

### CheckScreen.jsの新規作成

最後に `CheckScreen` コンポーネントを新規で作ります。このコンポーネントの役割は、 `this.props.hello` に保存された文字列をテキストで表示するだけです。

```javascript:CheckScreen.js
import React from 'react';
import { View, Text} from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { mapStateToProps, mapDispatchToProps } from './action.js';
import { styles } from './styles.js';

class CheckScreen extends React.Component {
  static navigationOptions = {
    title: "チェック画面"
  }

  render() {
    return (
      <View style={styles.container}>
        <Text>{ this.props.hello }</Text>
      </View>
    );
  }
}

CheckScreen.propTypes = {
  hello: PropTypes.string.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(CheckScreen);
```

これで最初に確認した動作が実現しました。
この時点でのソースコードは[hiroeorz/MobileExsampleのnaviブランチ](https://github.com/hiroeorz/MobileExample/tree/navi)にあります。

## サーバーとのHTTP通信

ここではアプリにほぼ必須の、サーバーとの通信のやり方を記します。
やることは、 `fetch` を使ってデータを取得し、取得したデータを先ほどのアクションクリエーター（ `action.js` )で定義した関数に流し込み、最終的に `reducer.js` で定義した処理を行うことで状態を更新し、その結果がViewに反映されます。

なお、情報を取得するのは 
[http://facebook.github.io/react-native/movies.json](http://facebook.github.io/react-native/movies.json)
から行います。

### 動作
先に、これから作る機能でどのようなことが実現するのか見ておきます。

トップ画面。ここで `HTTP API` と表示されたボタンをタップします。
<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/9ea047fb-e57f-8a51-b5d7-cd3724500680.png" height=400 />

続いて表示されるのは、ムービー情報取得ビュー。現時点では内容は空。
<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/6899e37c-4e86-c0ad-dd05-8279f4bf1672.png" height=400 />

`取得` ボタンをタップすると、サーバーから情報を取得して表示。

<img src="https://qiita-image-store.s3.amazonaws.com/0/13835/a2cc9619-e8fc-0277-aa63-4b9e6a435a80.png" height=400 />


### HttpScreen.jsの新規実装
まずは新たに、 `HttpScreen.js` というファイル名のコンポーネントを実装します。
ポイントは

1. 取得ボタンを設置して、タップされたら `_handleGetMovieList` 関数を実行。
2. `_handleGetMovieList` 内では `fetch` を使って先ほどのHTTP APIを叩きJSONを取得。
3. 取得したJSONをパースして `this.props.updateMovieList(responseJson)` に流し込む（updateMovieListはこの後実装します）。
4. `PropTypes` で渡されるオブジェクトをチェックしている

点です。

```javascript:HttpScreen.js
import React from 'react';
import { View, Text, Button, Alert } from 'react-native';
import { connect } from 'react-redux';
import { mapStateToProps, mapDispatchToProps } from './action.js';
import PropTypes from 'prop-types';

import { styles } from './styles.js';

class HttpScreen extends React.Component {
  static navigationOptions = {
    title: "HTTP通信"
  }

  render() {
    var movies = [];

    for (let i in this.props.movieList.movies) {
      var movie = this.props.movieList.movies[i];
      movies.push(<Text key={ i }> * { movie.title }</Text>);
    }

    return (
      <View style={styles.container}>
        <Button title="取得" onPress={ this._getMoviewList.bind(this) } />
        <Text>タイトル: { this.props.movieList.title }</Text>
        <Text>説明: { this.props.movieList.description }</Text>
        <Text>ムービー一覧</Text>
        { movies.map((m) => {return m;}) }
      </View>
    );
  }

  _getMoviewList(e) {
    return fetch('http://facebook.github.io/react-native/movies.json')
      .then((response) => response.json() )
        .then((responseJson) => {
          this.props.updateMoviewList(responseJson);
        })
      .catch((error) => {
        Alert.alert("通信エラーが発生しました");
        console.error(error);
      });
  }
}

HttpScreen.propTypes = {
  moviewList: PropTypes.shape({
    title: PropTypes.string.isRequired,
    description: PropTypes.string.isRequired,
    movieList: PropTypes.arrayOf({
      title: PropTypes.string,
      releaseYear: PropTypes.string
    })
  })
}

export default connect(mapStateToProps, mapDispatchToProps)(HttpScreen);
```


### action.jsにアクションを追加
次に、 `action.js` に `updateMovieList` を実装します。実装後のコードはこんな感じです。
ポイントは `{type: 'MOVIE_LIST', movieList: movieList}` というアクションオブジェクトを作ってdispatch関数に渡しているところです。

```javascript:action.js
import store from './store.js';

export function mapStateToProps(state) {
  return state;
}

export function mapDispatchToProps(dispatch) {
  return {
    /* テキストエリアの内容を state.hello に保存する */
    updateHello: (text) => {
      dispatch( {type: 'HELLO_WORLD', hello: text} );
    },

    /* movieListオブジェクトを state.movieListに保存する */
    updateMoviewList: (movieList) => {
      dispatch( {type: 'MOVIE_LIST', movieList: movieList} )
    }
  }
}
```

### reducer.jsにReducerを追加

続いて `reducer.js` を編集します。ポイントは

1. 最初に `const initialState` として状態の初期化を行うところで空の `movieList` オブジェクトを定義しています。
2. `action.type` が `'MOVIE_LIST'` の場合に、 `state.movieList` を受け取ったオブジェクトで更新します。

```javascript:reducer.js
const initialState = {
  hello: "Hello World",
  movieList: { title: "", description: "", movies: [] }
}

export default function reducer(state = initialState, action) {
  switch(action.type) {

    /* テキストエリアの内容を state.hello に保存する */
    case 'HELLO_WORLD':
      return {
        ...state,
        hello: action.hello
      };

    /* ムービー情報をJSONで取得したものを state.movieList に保存する */
    case 'MOVIE_LIST':
      return {
        ...state,
        movieList: action.movieList
      };

    default:
      return state
  }
}
```

### App.jsにてナビゲーターの追加

`HttpScreen.js` をインポートして `HttpScreen` へのナビゲーターを追加します。

```javascript:App.js
import React from 'react';
import { View } from 'react-native';
import { StackNavigator, addNavigationHelpers } from 'react-navigation';
import { Provider } from 'react-redux';

import { store } from './store.js';
import { styles } from './styles.js';
import Hello from './Hello.js';
import CheckScreen from './CheckScreen.js';
import HomeScreen from './HomeScreen.js';
import HttpScreen from './HttpScreen.js'; //追加！

const AppNavigator = StackNavigator({
  Home: {screen: HomeScreen},
  Hello: {screen: Hello},
  Check: {screen: CheckScreen},
  Http: {screen: HttpScreen}              //追加！
});

class App extends React.Component {
  render() {
    return (
      <Provider store={ store }>
        <AppNavigator />
      </Provider>
    )
  }
}

export default App;
```


### HomeScreen.jsにボタンを追加
最後に、 `HomeScreen.js` 内で、先ほど作った `HttpScreen` へジャンプするためのボタンを追加します。

```javascript:HomeScreen.js
import React from 'react';
import { View, Button } from 'react-native';

import { styles } from './styles.js';

class HomeScreen extends React.Component {
  static navigationOptions = {
    title: "ホーム"
  }

  render() {
    const { navigate } = this.props.navigation;

    return (
      <View style={styles.container}>
        <Button title="Hello" onPress={ () => navigate('Hello') } />
        <Button title="Check" onPress={ () => navigate('Check') } />
        <Button title="HTTP API" onPress={ () => navigate('Http') } />
      </View>
    );
  }
}

export default HomeScreen;
```

これで完了です。実行すればHTTP APIからデータを取得して表示します。

この時点でのソースコードは [hiroeorz/MobileExampleのhttpapiブランチ](https://github.com/hiroeorz/MobileExample/tree/httpapi)にあります。