【React Native】React Redux で通信処理をViewから独立させよう

# なぜ必要か
[【React Native】React Redux って覚えるの面倒だけど使うしかないよね](https://qiita.com/keneo/items/514ffc98102d95162f00) で、Reduxを導入しましたが、ステートの変更はUI操作だけでなく、通信を契機に変更されることもあります。ここでは通信処理をどのように記述していくかシンプルで具体的な導入例を示します。


# redux-thunk
redux は処理の合間にミドルウェアを挟んで柔軟な対応を可能としていますが、 redux-thunk は通常だとJSONのオブジェクトを定義する action に関数を記述可能にして、任意の処理を実行できるようにするミドルウェアです。
https://github.com/gaearon/redux-thunk

# 前提ライブラリ
本記事は、「NativeBase」、「React Navigation」の導入を前提としています。一からプロジェクトを作成する場合には、以下の記事を参考に環境作成してください。
[【React Native】NativeBase導入](https://qiita.com/keneo/items/d3a36d973c0b89829aa9)
[【React Native】React Navigation を使ってみる（画面遷移編）](https://qiita.com/keneo/items/b62ddcab0e35ce792b67)

## インストール
```
$ npm install redux-thunk --save
```
# 導入例

## Action
```js:actions.js
function requestStart() {
    return {
      type: 'REQUEST_MESSAGE',
    }
}
  
function receiveResponse(json) {
    return {
      type: 'REQUEST_MESSAGE_SUCCESS',
      response: json.response.prefecture
    }
}
  
export function fetchMessages() {
    return dispatch => {
        dispatch(requestStart())
        return fetch("http://express.heartrails.com/api/json?method=getPrefectures")
            .then(response => response.json())
            .then(function(json) {
                console.log(json);
                dispatch(receiveResponse(json))
            }).catch((response) => {
                console.log("err!");
            });
    }
}
```

### fetchMessages()
Componentからコールされるファンクションです。dispatchのコールでステートの変更が行われます。ここではfetchを使用して通信（※）を実施、それによりステート変更しています。

※無料で使用できるAPI[HeartRails (https://www.heartrails.com)](https://www.heartrails.com) を使用しています。

### requestStart()
通信を開始、通信状況のステート「isFetching」をtrueにするActionになります。

### receiveResponse()
受け取ったレスポンスをレスポンス（この場合は都道府県の情報）のステート「response」にセットするActionになります、通信終了のため「isFetching」はfalseにしています。

## Reducer
```js:reducers.js
import {combineReducers} from 'redux';

export const reducer = (state = {profile: ""}, action) => {  
    switch (action.type) {
      case 'REQUEST_MESSAGE':
        return Object.assign({}, state, {
          isFetching: true
      });

      case 'REQUEST_MESSAGE_SUCCESS':
        return Object.assign({}, state, {
          isFetching: false,
          response: action.response
      });
  
      default:
        return {...state}
    }
};

export const reducers = combineReducers({  
  reducer: reducer,
});
```
アクションに設定された「type」により各ステートの変更を行なっています。

## Component
```jsx:Home.js
import React, {Component} from 'react';
import { Container, View, Header, Left, Body, Right, Button, Content, Title, Text } from 'native-base';
import { connect } from 'react-redux';
import { fetchMessages } from './redux/actions';

export class HomeContainer extends Component {
  constructor(props) {
      super(props);
  }

  getPrefecture = () => {
    this.props.fetchMessages()
  }

  displayResponse = response => {
     if (!response) {
      return "";
    }
    return response.join();
  }

  render() {
  const props = this.props;
      return (
        <Container>
          <Header>
            <Left />
            <Body>
              <Title>メイン</Title>
            </Body>
            <Right />
          </Header>
          <Content>
            <View style={{display: 'flex', alignItems: 'center'}}>
              <View style={{justifyContent: 'center'}}><Text>{this.displayResponse(this.props.response)}</Text></View>
              <Button small block transparent primary onPress={this.getPrefecture}>
                <Text>都道府県を取得</Text>
              </Button>
            </View>
          </Content>
        </Container>
      );
  }
}

const mapStateToProps = state => ({
  response: state.reducer.response,
});
  
const mapDispatchToProps = {
  fetchMessages
};

export default connect(mapStateToProps, mapDispatchToProps)(HomeContainer);
```
ステート「response」を表示しています（displayResponseでステート解析、表示用の文字に変換）。ボタン押下により、Actionの「fetchMessages」を使用して、通信を実行、ステートが変化（都道府県情報が設定）して、表示される様子がわかります。

## 実際の表示
![ios.gif](https://qiita-image-store.s3.amazonaws.com/0/22218/45d421e1-99c5-1954-18f1-e9d1ccca11d5.gif)

# リポジトリ
本記事で作成したものは以下で公開していますので、参考にしてください。
https://github.com/k-neo/ReactNativeCourseReduxCommunication