ReactNative 簡単なSample集

ハンズオンに参加したので備忘録として残します。

## 環境設定

・インストール

``` command:command
$ brew install watchman
$ npm install -g react-native-cli
```

・作業場で環境構築

``` commnand:command
react-native init Native
cd Native
react-native run-ios // xcodeが立ち上がる
```

## ReactNativeとは

- Reactを用いてiOSやAndroidのネイティブアプリを構築できるフレームワーク
- JavaScriptからネイティブのAPIが呼ばれる
- どのプラットフォーム向けにも書けるようになる

## 基本文法

- divやspanなどのDOMを使えない
- DOMを使えない替わりに「View」や「Text」などコンポーンネントとして使う
- テキストを扱う場合は「Text」。入れ物として扱う場合は「View」
- CSSは使えないので、替わりにに「CSS in JS式」でスタイリングする

・例

``` javascript:sample
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';

<View style={styles.container}>
  <Text>テキスト</Text>
</View>

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

## flexを使ってレイアウトを作る

- ReactNativeでは基本スクロールが表示されません
- 親に「flex: 1」を指定すると子は100%から比率を決めます

``` javascript:sample
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={[styles.base, styles.box1]}>
          <Text style={styles.text}>I am 2.</Text>
        </View>

        <View style={[styles.base, styles.box2]}>
          <Text style={styles.text}>I am 5.</Text>
        </View>

        <View style={[styles.base, styles.box3]}>
          <Text style={styles.text}>I am 1.</Text>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  text: {
    fontSize: 24,
    color: 'white',
  },
  base: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  box1: {
    flex: 2,
    backgroundColor: 'black'
  },
  box2: {
    flex: 5,
    backgroundColor: 'red',
  },
  box3: {
    flex: 1,
    backgroundColor: 'yellow',
  },
});

AppRegistry.registerComponent('Native', () => App);
```

　・完成品
<img width="311" alt="01.png" src="https://qiita-image-store.s3.amazonaws.com/0/132855/730e737d-2a90-657a-e55c-759fef7d917b.png">

## inputに入力したものが反映される

- TextInpuｔで入力された値がTextに反映される

``` javascript:sample
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TextInput,
} from 'react-native';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
    }
  }

  _onChangeText = (text) => {
    this.setState({ text });
  }

  render() {
    const {
      text,
    } = this.state;

    return (
      <View style={styles.container}>
        <TextInput
          style={styles.input}
          onChangeText={this._onChangeText}
          underlineColorAndroid='transparent'
        />
        <Text>{text}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  input: {
    height: 30,
    width: 200,
    borderBottomWidth: 1,
    borderBottomColor: '#008080',
  }
});

AppRegistry.registerComponent('Native', () => App);
```

・完成品
<img width="219" alt="02.png" src="https://qiita-image-store.s3.amazonaws.com/0/132855/aff9ca3d-0d69-eac5-fe71-26dcf1961aef.png">

## input入力したものをリスト表示

- TouchableOpacity、FlatListを使って実装
- onPress、renderItemを使って実装

``` javascript:sample
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TextInput,
  TouchableOpacity,
  FlatList,
} from 'react-native';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
      list: [],
      listCount: 0,
    }
  }

  _onChangeText = (text) => {
    this.setState({ text });
  }

  _onPress = () => {
    const {
      list,
      text,
      listCount,
    } = this.state;
    const _list = list.concat();
    _list.push({
      key: listCount,
      text,
    });

    this.setState({
      text: '',
      list: _list,
      listCount: this.state.listCount + 1,
    });
  }

  render() {
    const {
      list,
      text,
    } = this.state;

    return (
      <View style={styles.container}>
        <View style={styles.inputArea}>
          <TextInput
            style={styles.input}
            onChangeText={this._onChangeText}
            underlineColorAndroid='transparent'
            value={text}
          />
          <TouchableOpacity
            style={styles.button}
            onPress={this._onPress}
          >
            <Text style={styles.buttonText}>Add</Text>
          </TouchableOpacity>
        </View>
        <FlatList
          data={list}
          renderItem={({item}) => <Text key={item.key} style={styles.itemText}>{item.text}</Text>}
          style={styles.list}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  inputArea: {
    flexDirection: 'row',
    marginTop: 64,
  },
  input: {
    height: 30,
    width: 200,
    borderBottomWidth: 1,
    borderBottomColor: '#008080',
    marginRight: 20,
  },
  button: {
    width: 80,
    height: 40,
    backgroundColor: '#006060',
    justifyContent: 'center',
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 20,
  },
  list: {
    width: 300,
  },
  itemText: {
    fontSize: 22,
    margin: 10,
  }
});

AppRegistry.registerComponent('Native', () => App);
```

・完成品
<img width="267" alt="03.png" src="https://qiita-image-store.s3.amazonaws.com/0/132855/0489f1d3-fec3-3c97-807b-331437164dda.png">


## listをクリックすると打ち消し線をつける

- 1つのリストをクリックすると全てのlistに打ち消し線がつく(不具合)
- 打ち消し線の有無をstateを使ってBoolean処理

``` javascript:sample
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TextInput,
  TouchableOpacity,
  FlatList,
} from 'react-native';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
      list: [],
      listCount: 0,
      listPressBoolean: false,
      listThrough: true,
    }
  }

  _onChangeText = (text) => {
    this.setState({ text });
  }

  _onPress = () => {
    const {
      list,
      text,
      listCount,
    } = this.state;
    const _list = list.concat();
    _list.push({
      key: listCount,
      text,
    });

    this.setState({
      text: '',
      list: _list,
      listCount: this.state.listCount + 1,
    });
  }

  _listOnPress = () => {
    const {
      listPressBoolean,
      listThrough,
    } = this.state;

    this.state.listPressBoolean ? this.setState({ listThrough: true, listPressBoolean: false}) : this.setState({ listThrough: false, listPressBoolean: true});
    this.setState({
      list: this.state.list.concat(),
    })
  }

  render() {
    const {
      list,
      text,
      listThrough,
    } = this.state;

    return (
      <View style={styles.container}>
        <View style={styles.inputArea}>
          <TextInput
            style={styles.input}
            onChangeText={this._onChangeText}
            underlineColorAndroid='transparent'
            value={text}
          />
          <TouchableOpacity
            style={styles.button}
            onPress={this._onPress}
          >
            <Text style={styles.buttonText}>Add</Text>
          </TouchableOpacity>
        </View>
        <FlatList
          data={list}
          renderItem={({item}) => <Text key={item.key} style={listThrough ? styles.itemText : styles.lineThrough} onPress={this._listOnPress}>{item.text}</Text>}
          style={styles.list}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  inputArea: {
    flexDirection: 'row',
    marginTop: 64,
  },
  input: {
    height: 30,
    width: 200,
    borderBottomWidth: 1,
    borderBottomColor: '#008080',
    marginRight: 20,
  },
  button: {
    width: 80,
    height: 40,
    backgroundColor: '#006060',
    justifyContent: 'center',
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 20,
  },
  list: {
    width: 300,
  },
  itemText: {
    fontSize: 22,
    margin: 10,
  },
  lineThrough: {
    fontSize: 22,
    margin: 10,
    textDecorationLine: 'line-through',
  }
});

AppRegistry.registerComponent('Native', () => App);
```

・完成品
<img width="259" alt="04.png" src="https://qiita-image-store.s3.amazonaws.com/0/132855/a804a3b5-1070-c99d-42c2-be1b315be33b.png">



## 参考サイト(引用サイト)

- [YutamaKotaro/slides](https://github.com/YutamaKotaro/slides/blob/master/Native.md)
- [React Native Japan](https://react-native-meetup.connpass.com/)