React Native - Redux ecosystem(redux-form)

Reduxを利用することの利点は、Fluxアーキテクチャを組み込むことだけではありません。Reduxはかなり熱いフレームワークであり、Reduxのエコシステムができています。

[awesome-refux](https://github.com/xgrommx/awesome-redux)にはExampleだけじゃなくライブラリも列挙されてます。必ずしもReact Nativeで利用できるかは保証できませんが、ライブラリのgithub issueやコードを覗くとReactNativeがサポートされているような記述を見つけることができます。storageやi18nのライブラリもあるので、Nativeでそれらのエコシステムを利用し、開発スピードを上げることができます。

今回は、ecosystemライブラリの一つであるRedux-formのReact Nativeにどうやって組み込むかを説明します。

## redux-form

https://github.com/erikras/redux-form

HTMLでいうとinputなどのフォームを作るライブラリです。Nativeでもログイン画面などText入力を受けつけるので、これを使うことでFormのvalidation等を実装できます。

### Install redux-form

Redux本体と同じくReactNativeのReact0.14互換対応待ちなので少し古いバージョンで動かします。`package.json`に下記の行を追加し、`npm install`してインストールします。

```
  "dependencies": {
    "redux-form": "^3.0.11",
```

### コード

Formを組み込みたいでredux-formを呼び出します。これもredux本体と同じように`redux-form/native`でimportする形になります。

```
import {reduxForm} from 'redux-form/native';
```

storeと`reuxForm()`でコンポーネント（下記の例ではLogin）との関連付けを行います。form名、フィールドを使うかを記述します。

```
export default reduxForm({
  form: 'login',
  fields: ['email', 'password']
})(Login);
```

そして、いつものようにpropsからStoreのstateを取得します。
```
   const {dispatch, fields: { email, password }, handleSubmit } = this.props;
```

`{...email}`を入力部に入れれば完成です。

```
        <TextInput
          style={Styles.inputText}
          {...email}
          placeholderTextColor="#ccc"
          keyboardType='email-address'
        />
```

ここにemail validationを追加したい場合は、validationを作り、

```
const validate = values => {
  const errors = {};
  if (!values.email) {
    errors.email = 'Required';
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = 'Invalid email address';
  }
  return errors
}
```

`reduxForm()`に読み込ませます。

```
//export default Login;
export default reduxForm({
  form: 'login',
  validate, //追加
  fields: ['email', 'password']
})(Login);
```

すると、下記のようにInvalidというメッセージが表示されます。

![スクリーンショット 2015-12-10 22.35.24.png](https://qiita-image-store.s3.amazonaws.com/0/13663/963d7c85-d8b2-442d-6f87-2a77a72a9b1e.png)

全体のコードは下記のようになります。

```
import React, { Text, View, TextInput } from 'react-native';
import {reduxForm} from 'redux-form/native';
import { login } from '../actions';
import Button from 'react-native-button';
import Styles from '../components/Styles';

const validate = values => {
  const errors = {};
  if (!values.email) {
    errors.email = 'Required';
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = 'Invalid email address';
  }
  return errors
}

let Login = React.createClass({

  getInitialState(){
    return {
      email: "",
      password: "",
    }
  },

  render(){
   const {dispatch, fields: { email, password }, handleSubmit } = this.props;
    return (
      <View>
        <Text style={Styles.label}>Email</Text>
        <View style={Styles.separator} />
        <TextInput
          style={Styles.inputText}
          {...email}
          placeholderTextColor="#ccc"
          keyboardType='email-address'
        />
        {email.touched && email.error && <Text>{email.error}</Text>}
        <View style={Styles.separator} />
        <Text style={Styles.label}>Password</Text>
        <View style={Styles.separator} />
        <TextInput
          style={Styles.inputText}
          {...password}
          secureTextEntry={true}
          placeholderTextColor="#ccc"
        />
        <View style={Styles.separator} />
        <Button onPress={handleSubmit(data => dispatch( login(data.email, data.password) ))} style={{marginTop: 20, color: '#F0614F'}}>Login</Button>
      </View>
    )
  }
});

//export default Login;
export default reduxForm({
  form: 'login',
  validate,
  fields: ['email', 'password']
})(Login);
```

## Summary

今日はReduxのecosystemを利用して、React Nativeのアプリを書いてみました。まさにLearn once, write anywhere"ですね。Web技術がそのままNativeで生きてきます。まだ沢山Reduxのecosystemライブラリがあるので是非試してみてください。