Igniteを使ってみる1

ReactNativeのラッパーフレームワーク的な存在のigniteを使ってみようと思います。
サンプル集のような感じでかなりの量のコンポーネントのサンプルが出来上がっています。
サンプルコピペでいい感じにアプリがつくれないかなーと思ったのでちょっと触っています。

[Ignite](https://github.com/infinitered/ignite)
　ReactNativeのラッパーフレームワークでコードを読めばコーディングの仕方が見えてきます。
[Ignite Plugin](https://github.com/infinitered/ignite/blob/master/PLUGINS.md)
　プラグインもたくさんあるので時間があるときに使ってみたいです。
[今回作成したコード](https://github.com/MariMurotani/PizzaApp/blob/add_test_screen/App/Containers/TestScreen.js)
[ReactNatveDebugger](http://qiita.com/y_koh/items/3f2090e450269bc9f07c)
　を参考にCtrl+DでChromeを使ってデバックできるようにしておく


# 1. 前提条件
1. Xcodeのインストール
2. AndroidSDKのインストール
3. NodeJSのインストール
４． OS等

|  |       Right align |
|-----------------|------------------:|
| ProductName | Mac OS X |
| ProductVersion | 10.11.6 |
| BuildVersion | 15G31 |
| Ruby | 2.3.0 |
| Npm | 3.10.8 |

# 2. Igniteのインストール
```
ignite new PizzaApp

-----------------------------------------------

An unfair headstart for your React Native apps.
https://infinite.red/ignite

-----------------------------------------------

🔥 igniting app PizzaApp
✔ using the Infinite Red 2016 boilerplate
✔ added React Native 0.42.0
? Would you like Ignite Development Screens? Yes
? What vector icon library will you use? react-native-vector-icons
? What internationalization library will you use? none
? What animation library will you use? react-native-animatable
✔ added ignite-ir-boilerplate-2016
✔ added ignite-dev-screens
✔ added ignite-vector-icons
✔ added ignite-animatable
✔ configured git1
🍽 Time to get cooking!

To run in iOS:
  cd PizzaApp
  react-native run-ios

To run in Android, make sure you've followed the latest react-native setup instructions at https://facebook.github.io/react-native/docs/getting-started.html before using ignite.
You won't be able to run react-native run-android successfully until you have. Then:
  cd PizzaApp
  react-native run-android

To see what ignite can do for you:
  cd PizzaApp
  ignite

```

IOSエミュレータで確認してみます。

```
cd PizzaApp
react-native run-ios
```

# 3. シーンを一つ追加してみる
### 3.1 .ES6の書き方に慣れるまで一苦労ですが、importで必要なモジュールをインポートします。

```javascript:App/Containers/TestScreen.js
// @flow
'use strict'
import React from 'react'
import { View, Text, Image, ListView, StyleSheet, TouchableHighlight } from 'react-native'
import { Metrics } from '../Themes'
// import R from 'ramda'

// Styles
import styles from './Styles/LaunchScreenStyles'
// URL feed
var REQUEST_URL = 'https://lingohub.com/blog/feed/json?v=2.0&num=200&q=http://feeds.reuters.com/reuters/businessNews'
```

### 3.2. [React.Component](https://facebook.github.io/react/docs/react-component.html)を継承したTestScreenクラスを作成

```javascript
export default class TestScreen extends React.Component {
  // コンストラクタ
  constructor (props) {
    super(props)
    // ステートの設定
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2
      }),
      title: '',
      description: '',
      loaded: false
    }
    // データ取得
    this.fetchData()
  }
}

```

### 3.3. データ取得の実体部分を記載
上記でthis.fetchData()としている部分の中身を記載します。constructorの後にメソッドを追加しましょう。
REQUEST_URLに記載のURLからFeedを取得しています。
取得したデータを[ステート管理](https://facebook.github.io/react/docs/react-component.html#setstate)に追加します。

> setState()はコンポーネントの状態変化をキューにいれて、更新が必要なReactコンポーネントとその子コンポーネントに知らせます。
これはイベントハンドラやサーバーレスポンスによるユーザーインターフェイスの更新に必要な初期的な手続きです。

と書いてあるので、非同期イベントからのレスポンスを受け取ったらとりあえずsetState()に入れると覚えておきましょう！
ちなみに、”パフォーマンスの効率化の為にただちにコンポーネントを更新するのではなく、単一回路で複数のコンポーネントを一度に更新します。
Reactはstateの変更がコンポーネントの変更にただちに適用される事を保証しません！”
と書いてありますのでデータ更新と画面更新が非同期である認識くらいは持っておきましょう。

```javascript
  // データ取得用
  fetchData () {
    fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        // ステートに値を設定
        this.setState({
          title: 'Test Title',
          description: 'Test Description',
          dataSource: this.state.dataSource.cloneWithRows(responseData),
          loaded: true
        })
        this.render()
      })
      .done()
  }

```

### 3.4. 画面のレンダリング部分を実装
上記でthis.render()としている部分の中身を記載します。先程の続きに記述して行きましょう。
constructor()の中でstate.loadedという値を初期化しています。fetchData()でデータfetch後にフラグをfalseから　trueに変更しています。
データ取得前はloading表示、その後はListView()をレンダーするという動作になっています。

```javascript
  //  描画用のrender
  render () {
    if (!this.state.loaded) {
      return this.renderLoadingView()
    }
    return this.renderListView()
  }
  //  ローディング用の表示をする
  renderLoadingView () {
    return (
      <View style={styles.mainContainer}>
        <Text>Loading......</Text>
      </View>
    )
  }

```

### 3.5. データをコンポーネントに描画
上記でrenderListView()というメソッドを読んでいるのでその中身を記載していきます。
[ListView](https://facebook.github.io/react-native/docs/listview.html)というReactではよく使われるであろうコンポーネントを利用しています。

1. dataSourceに3.3.で設定したdataSourceを指定
2. 行ごとのレンダリング:renderRow=にrenderListViewRows()を指定
3. styleにスタイルを指定
4.その他に下記のコンポーネントも利用しています。

[TouchableHighlight](http://facebook.github.io/react-native/releases/0.45/docs/touchablehighlight.html#touchablehighlight)　- タッチ領域用
[View](http://facebook.github.io/react-native/releases/0.45/docs/view.html#view)　- 言わずとしれたViewですが、ルートのViewは必ず一つでないといけませんので、　ルートViewの中にデザインを記載します。
[Image](http://facebook.github.io/react-native/releases/0.45/docs/image.html#image) - 画像表示用のコンポーネント

```javascript
  //  リスト用の表示をする
  renderListView () {
    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderListViewRows.bind(this)}
        style={styles.mainContainer}
      />
    )
  }
  //  一行ごとの
  renderListViewRows (entry) {
    return (
      <TouchableHighlight onPress={() => {
        this.onClickRow(entry)
      }}>
        <View style={ListStyles.container}>
          <Image
            source={{uri: entry.thumbnail}}
            style={ListStyles.thumbnail}
          />
          <View style={ListStyles.rightContainer}>
            <Text style={ListStyles.title}>{entry.title}</Text>
            <Text style={ListStyles.year}>{entry.date}</Text>
          </View>
        </View>
      </TouchableHighlight>
    )
  }

```

### 3.5. スタイルの設定
上記のコードで**style=**　でスタイル指定する部分が多くなってきたのでこちらの指定をします。
TestScreenクラスの外側にただの変数として定義します。

```javascript
//  スタイル
var ListStyles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'flex-start',
    backgroundColor: '#F5FCFF'
  },
  rightContainer: {
    flex: 1,
    alignItems: 'stretch'
  },
  title: {
    fontSize: 16,
    textAlign: 'left',
    flexWrap: 'wrap'
  },
  year: {
    fontSize: 12,
    textAlign: 'right',
    flexWrap: 'wrap'
  },
  thumbnail: {
    width: 53,
    height: 53
  },
  listView: {
    marginTop: Metrics.navBarHeight,
    paddingTop: 20,
    backgroundColor: '#F5FCFF'
  }
})

```

### 3.6. クリックイベントの設定
TestScreenクラスの中にクリックイベントを追加します。
onClickRowは3.5.で定義したrenderListViewRows()の中に記載がある事を確認しましょう！

```javascript:
 onPress={() => {
        this.onClickRow(entry)
      }
```

console.log(entry)で行ごとのdataソースが取得できるはずです。
Actions.testDetailにentryを渡して次のスクリーンを表示します。

```js
  //  行をクリック
  onClickRow (entry) {
    window.alert('onClickRow: ' + entry.title)
    console.log(entry)
    console.log(this)
    Actions.testDetail(entry)
  }
```
### 3.7. 詳細ページの追加
リストを表示した後に詳細ページを表示するためにもう一つシーンを追加します。

```javascript:App/Containers/TestDetail.js

// @flow
'use strict'
import React from 'react'
import { View, Text, Image, StyleSheet } from 'react-native'
import styles from './Styles/LaunchScreenStyles'

export default class TestDetail extends React.Component {
  constructor (props) {
    super(props)

    this.state = {
      loaded: false
    }
  }
  //  描画用のrender
  render () {
    return this.renderView()
  }
  //  リスト用の表示をする
  renderView () {
    console.log('detail view')
    console.log(this.props)
    return (
    <View style={styles.mainContainer}>
        <Text>TEST</Text>
        <Text>{this.props.title}</Text>
        <Image
          source={{uri: this.props.thumbnail}}
        />
        <Text>{this.props.author}</Text>
      </View>
    )
  }
}

//  スタイル
var ListStyles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'flex-start',
    backgroundColor: '#F5FCFF'
  }
})


```

### 3.8. ナビゲータにスクリーンを登録
TOPページにボタンを追加して作成したスクリーンに移動してみましょう。
TestScreenとTestDetailを追加します。

```javascript:/App/Navigation/NavigationRouter.js

'use strict'
import React from 'react'
import { View, Text, Image, StyleSheet, TouchableHighlight } from 'react-native'

class NavigationRouter extends Component {
   .....
            <Scene key='testScreen' component={TestScreen} title='TestScreen' />
            <Scene key='testDetail' component={TestDetail} title='TestDetault' /
   .....
}

```

### 3.9. HOMEページにボタンを追加
起動画面に先程作ったTestScreenに遷移する記述を追加します。

```javascript:App/Containers/LaunchScreen.js
.......
          <RoundedButton onPress={this.goToNext}>
            Go To My Example
          </RoundedButton>
.......
```

# 4. 厳しすぎる構文チェックへの対処
Igniteのフレームワークではgit-hookを使って構文チェックをしています。
同じチェックをコマンドラインで実行できるのですが、修正を自動化していきたいと思います。
[StandardJS](https://standardjs.com/)

1 . インストール

```
npm install standard --save-dev
```

2 . 構文チェック確認

```
npm run precommit
```
3 . 構文修正

```
npm run fixcode
```