React Native Elements でイケてるUIを作る

## どんな記事？:star2: 
React Nativeのスター1万超えのUIライブラリ 
[React Native Elements](https://github.com/react-native-training/react-native-elements)
の使用方法についてまとめた記事です。
今回はプロジェクトを作るところから始めてみます。

<img width="1440" alt="スクリーンショット 2018-05-19 18.07.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/99874/87e36084-8db9-58c1-4e4d-2cce8d490741.png">

また、バージョンは `0.19.0`を使用しております。

また、[@y_tsubuku](https://twitter.com/y_tsubuku)が開発する[yaritori - メール共有システム](https://yaritori.jp/)も、良ければご覧ください :tada: 

## プロジェクトを作成 :rocket: 
[create-react-native-app](https://facebook.github.io/react-native/docs/getting-started.html)でさくっと。

```bash
# プロジェクト作成
$create-react-native-app elements_example
# 作ったプロジェクトのルートディレクトリへ移動
$cd elements_example
# 起動
$yarn start
```
起動時はこんなかんじ
![Simulator Screen Shot - iPhone 6 Plus - 2018-05-19 at 18.25.55.png](https://qiita-image-store.s3.amazonaws.com/0/99874/8cb9036b-a1b5-3f7b-4617-7197746e99cd.png)

また、`App.js`はこんなかんじになっています。

```jsx:App.js
import React from 'react';
import { StyleSheet, Text, View } 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>
      </View>
    );
  }
}

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

作成+起動を確認できたので、続いてReact Native Elementsをインストールしていきましょう。

## React Native Elementsをインストール :package: 
```bash
$yarn add react-native-elements
```
これでエラーなどでなければOK。
それでは、実際に動かしながら試していきましょう。

※React Native Elementsには多くのComponentが含まれます。
「全部みたいよ〜」という方は、[Overview](https://react-native-training.github.io/react-native-elements/docs/0.19.0/avatar.html)から探すと良さそうです。

## [Avatar](https://react-native-training.github.io/react-native-elements/docs/0.19.0/avatar.html)
* ユーザアイコンなどに。
* 表示はイメージ・文字・アイコンから選択可能。
* サイズは、 `small`, `medium`, `large`, `xlarge`から選べる。
* propsに`rounded`を付加すると、丸くしてくれる。
* まさにAvatar。使いやすいですね。

![Simulator Screen Shot - iPhone 8 - 2018-05-19 at 20.02.28.png](https://qiita-image-store.s3.amazonaws.com/0/99874/511fba4d-2641-44a5-41fe-a0fa8ce19553.png)



```jsx:Avatar.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Avatar } from 'react-native-elements'

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Avatar
          small
          rounded
          source={{uri: "https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192"}}
          onPress={() => console.log("Works!")}
          activeOpacity={0.7}
        />
        <Avatar
          medium
          rounded
          source={{uri: "https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192"}}
          onPress={() => console.log("Works!")}
          activeOpacity={0.7}
        />
        <Avatar
          large
          rounded
          source={{uri: "https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192"}}
          onPress={() => console.log("Works!")}
          activeOpacity={0.7}
        />
        <Avatar
          xlarge
          rounded
          source={{uri: "https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192"}}
          onPress={() => console.log("Works!")}
          activeOpacity={0.7}
        />
        <Avatar
          xlarge
          rounded
          title="津"
          onPress={() => console.log("Works!")}
          activeOpacity={0.7}
        />
        <Avatar
          xlarge
          rounded
          icon={{name: 'user', type: 'font-awesome'}}
          onPress={() => console.log("Works!")}
          activeOpacity={0.7}
        />
      </View>
    );
  }
}

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

※アイコンがうまくでないよーって人 :hand_splayed: 
[Icon in Avatar doesn't work](https://github.com/react-native-training/react-native-elements/issues/772#issuecomment-350448350)
あたりが参考になるかも。

## [Button](https://react-native-training.github.io/react-native-elements/docs/0.19.0/button.html)

* ボタン
* `raised`で浮き上がらせたり、`large`で大きくしたり。
* actionは`onPress`や`onLongPress`で付けられる。

![Simulator Screen Shot - iPhone 8 - 2018-05-19 at 19.52.59.png](https://qiita-image-store.s3.amazonaws.com/0/99874/934b5328-0004-a0dc-4360-aac208b81faa.png)



```jsx:Button.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Button } from 'react-native-elements'

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Button
          backgroundColor="#ff5622"
          title='普通のボタン'
          style={styles.button}/>
        <Button
          backgroundColor="#ff5622"
          title='onPress/onLongPress'
          style={styles.button}
          onPress={() => console.log('押されたよ')}
          onLongPress={() => console.log('長く押されたよ')}/>/>
        <Button
          raised
          backgroundColor="#009588"
          title='RAISED（ちょっと浮き上がる）'
          style={styles.button}/>
        <Button
          icon={{name: 'cached'}}
          backgroundColor="#9c26b0"
          title='アイコン付き'
          style={styles.button}/>
        <Button
          large
          backgroundColor="#8ac34a"
          title='largeだとこのくらいの大きさ'
          style={styles.button}/>
        <Button
          large
          iconRight={{name: 'code'}}
          backgroundColor="#ffc107"
          title='右にもアイコンを付けられる'
          style={styles.button}/>
        <Button
          large
          backgroundColor="#25292f"
          icon={{name: 'mark-github', type: 'octicon'}}
          title='OCTICONも使える'
          style={styles.button}/>

      </View>
    );
  }
}

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

## [Card](https://react-native-training.github.io/react-native-elements/docs/0.19.0/card.html)

* なんだかんだで便利なCard
* Card + 何か で使うことが多くなると思います

![Simulator Screen Shot - iPhone 8 - 2018-05-19 at 21.29.19.png](https://qiita-image-store.s3.amazonaws.com/0/99874/149b8adb-db36-cccd-af33-488f6fac11a9.png)

```jsx:Card.js
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { Card, ListItem, Button } from 'react-native-elements'

const users = [
  {
    name: 'こんな',
    avatar: 'https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192'
  },
  {
    name: 'ふうに',
    avatar: 'https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192'
  },
  {
    name: 'リスト形式で',
    avatar: 'https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192'
  },
  {
    name: '出せます',
    avatar: 'https://qiita-image-store.s3.amazonaws.com/0/99874/profile-images/1511169192'
  },
]

export default class App extends React.Component {
  constructor(props) {
    super(props);
  }


  render() {
    return (
      <View style={styles.container}>
        <Card containerStyle={{padding: 0}}>
          {
            users.map((u, i) => {
              return (
                <ListItem
                  key={i}
                  roundAvatar
                  title={u.name}
                  avatar={{uri: u.avatar}}
                />
              );
            })
          }
        </Card>

        <Card
          title='メディア系でよくあるカード'
          image={{uri: 'https://qiita-image-store.s3.amazonaws.com/0/99874/87e36084-8db9-58c1-4e4d-2cce8d490741.png'}}>
          <Text style={{marginBottom: 10}}>
            割りと簡単に出せますね。便利かも。長いと勝手に改行されます
          </Text>
          <Button
            icon={{name: 'eye', type: 'octicon'}}
            backgroundColor='#03A9F4'
            title='もっとみる'/>
        </Card>

      </View>
    );
  }
}

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

## [Divider](https://react-native-training.github.io/react-native-elements/docs/0.19.0/divider.html)
* シンプルな区切り線

![Simulator Screen Shot - iPhone 8 - 2018-05-19 at 20.52.17.png](https://qiita-image-store.s3.amazonaws.com/0/99874/6c3460d1-af92-a9a6-15e5-8a72be455143.png)

```jsx:Divider.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Divider } from 'react-native-elements'

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Divider style={{ backgroundColor: 'blue' }} />
      </View>
    );
  }
}

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

## [Form](https://react-native-training.github.io/react-native-elements/docs/0.19.0/forms.html)

* `FormLabel`にフォーム用のラベル
* `FormInput`に表示、入力時の処理
* `FormValidationMessage`にバリデーションエラーメッセージ
  * ただの赤いテキストがでるだけ(propsのlabelStyleで変更可能)なので、バリデーションロジックは自分で実装しないといけない。

![Simulator Screen Shot - iPhone 8 - 2018-05-19 at 21.06.41.png](https://qiita-image-store.s3.amazonaws.com/0/99874/c89bee90-b4f8-7038-d3a1-565d22bcb403.png)

```jsx:Form.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { FormLabel, FormInput, FormValidationMessage } from 'react-native-elements'

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

  requiredMessage = input => {
    return input === '' ? <FormValidationMessage>入力して下さい</FormValidationMessage> : <View/>
  };


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

    return (
      <View style={styles.container}>
        <FormLabel>名前</FormLabel>
        <FormInput
          onChangeText={name => this.setState({name})}
          value={name}/>
        {this.requiredMessage(name)}

        <FormLabel>メールアドレス</FormLabel>
        <FormInput
          onChangeText={email => this.setState({email})}
          value={email}/>
        {this.requiredMessage(email)}
      </View>
    );
  }
}

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

## SearchBar
* イケてる検索バー
* `round`を指定すれば、インプットの四隅が丸くなる
* `lightTheme`を指定すれば、ライトグレーのような薄い基調になる
* `icon`で、標準のアイコン（ルーペ）から、自分で指定したアイコンに、から変更できる

![Simulator Screen Shot - iPhone 8 - 2018-05-19 at 21.39.21.png](https://qiita-image-store.s3.amazonaws.com/0/99874/c2fd5d2a-aa24-afb5-23ba-c9135055fcec.png)


```jsx:SearchBar.js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { SearchBar } from 'react-native-elements'

export default class App extends React.Component {
  constructor(props) {
    super(props);
  }


  render() {
    return (
      <View style={styles.container}>
        <SearchBar
          onChangeText={text => console.log(text)}
          onClearText={text => console.log(text)}
          placeholder='検索キーワード…'/>

        <SearchBar
          noIcon
          placeholder='noIconでアイコン消せる'/>

        <SearchBar
          round
          placeholder='roundで丸く'/>

        <SearchBar
          lightTheme
          placeholder='lightTheme'/>

        <SearchBar
          lightTheme
          icon={{type: 'octicon', name: 'squirrel'}}
          placeholder='アイコンは自分で指定することも可能'/>
      </View>
    );
  }
}

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

## 終わりに :tada: 
コンポーネントの量が多く、全ては紹介しきれませんでしたが、導入の手助けになれば幸いです。

次はこれらのコンポーネントを利用して、実践的な内容に入っていきます。

twitter: [@y_tsubuku](https://twitter.com/y_tsubuku) やってるので、お気軽にフォローしてください :ocean: