ReactNativeだとカメラアプリくらいなら1時間で作れた

# 環境準備 :helmet_with_cross:

環境準備については、[ReactNativeはじめの一歩(Create React Native App)](https://qiita.com/yotasasaki/items/ee1fd72a8ba25c6fe27e) に書きました。

最近React Nativeの門を叩いたばかりで手探り状態ですが、まずは一番それっぽいものを、と思い、カメラアプリを作ってみることにしました。

ExpoにAPIが用意されていたり、先人達がすでに試されていたりして、それを見ながら大変簡単に実装することが出来ました。(というかExpoのドキュメントまんまでですが)

なお、iosを前提としています(Android未確認)

# カメラモジュール色々 :camera_with_flash: 
調べてみると幾つかのモジュールが存在しているようです。

* Expo.io
https://docs.expo.io/versions/latest/sdk/imagepicker.html
カメラだけでなく様々なAPIが用意されています。見てるだけでワクワクします。

* React Native Camera 
https://github.com/lwansbrough/react-native-camera
写真、ビデオ、バーコードスキャンも対応しているらしい。 Fork、Star数は多め。

* React Native Image Picker
https://github.com/react-community/react-native-image-picker
こちらも比較的開発は活発で、いずれ試してみたい。

# Expo.io SDK :iphone: 
今回はExpo.io SDKを使って簡単なカメラアプリを試してみました。

# 出来ることイメージ :rocket: 
* メイン画面
 
<img width="300" alt="image4.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/87716/0974f3ed-0820-451b-69f7-a9d7e559767a.jpeg">

* カメラとビデオ

<img width="300" alt="image1.png" src="https://qiita-image-store.s3.amazonaws.com/0/87716/fd69712a-f04f-2882-d67e-f81bd6767492.png">

* 位置調整

<img width="300" alt="image7.png" src="https://qiita-image-store.s3.amazonaws.com/0/87716/8b9d54a2-32b0-ead7-3c30-3a7096c3398c.png">


* 選択後のメイン画面

<img width="300" alt="image3.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/87716/a24c4d47-4695-3fc6-9656-41199ee25d69.png">

* ライブラリから選択

<img width="300" alt="image3.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/87716/0cf44863-a9a2-aa29-eb26-61a4a3ac0a3f.png">




# コード :pencil: 

```js:App.js
import React from 'react';
import { Button, Image, View } from 'react-native';
import { ImagePicker } from 'expo'; // ...(1)

export default class ImagePickerExample extends React.Component {
  state = {
    image: null,  // ...(2)
  };

  render() { // ...(3)
    let { image } = this.state; // ...(4)

    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Button
          title="Pick an image from camera roll"
          onPress={this._pickImage}
        />
        <Button
          title="Enjoy Camera!"
          onPress={this._camera}
        />
        {image &&
          <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
      </View>
    );
  }
  _camera = async () => { // ...(6)
    let result = await ImagePicker.launchCameraAsync();
    
    console.log(result)

    if (!result.cancelled) {
      this.setState({ image: result.uri });
    }

  };

  _pickImage = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      allowsEditing: true,
      aspect: [4, 3],
    });

    console.log(result);

    if (!result.cancelled) {
      this.setState({ image: result.uri });
    }
  };
}
```


#### (1) コンポーネントのimport

* まず冒頭で必要なコンポーネントを呼び出します。
  * [Button](https://facebook.github.io/react-native/docs/button.html) 
  ボタンのデザイン、文言、押下時の挙動など出来る
  * [Image](https://facebook.github.io/react-native/docs/image.html) 
  ローカルストレージや、ウェブ上の画像などを簡単に表示出来る
  * [View](https://facebook.github.io/react-native/docs/view.html) 
  UIを構築するための基本コンポーネント  

#### (2) state初期化

* 続いて、初期状態を指定します。  
  この[state](https://facebook.github.io/react-native/docs/state.html)というのは変化しうる状態を表すのに使われる変数です。もうひとつ[props](https://facebook.github.io/react-native/docs/props.html)という、ランタイムで不変な変数と共に語られています。

#### (3) render

* 次に、JSXをレンダリングするrender関数を作成します。

#### (4) imageの状態保存

`image`には現在の状態を代入します。
この `let {var} = this.obj` という書き方はオブジェクトの分割代入という構文で、`this.state` の `image` というプロパティが自動的に `let image` にセットされます。 

#### (5) `View`を記述します

`View`にはstyleが指定出来き、[View Style Props
](https://facebook.github.io/react-native/docs/view-style-props.html#Props)や[Layout Props](https://facebook.github.io/react-native/docs/next/layout-props.html) あたりを指定できます。 [flex]()を使用すると、さまざまな画面サイズで一貫したレイアウトを描画することが出来ます。

`Button`も同様で、[色や押下時のコールバック](https://facebook.github.io/react-native/docs/button.html#Props)なんかを指定できるようです。

また、`image`が`null`でなければ`<Image>`コンポーネントで描画します。
初期は`null`ですが、端末のライブラリから画像を選択したり撮影をした後に実行される、

```
    if (!result.cancelled) {
      this.setState({ image: result.uri });
    }
```
で、端末の画像のURI(file:///var/mobile...)が代入されています。

スタイルについてはいずれも、html/cssと遠くない記述ができるので、直感的に実装できそうです。

#### (6) 具体的な処理追加

次に、カメラ、画像選択時の具体的な処理を書いていきます。

カメラ -> [ImagePicker.launchCameraAsync](https://docs.expo.io/versions/latest/sdk/imagepicker.html#expoimagepickerlaunchcameraasyncoptions)
画像選択 -> [ImagePicker.launchImageLibraryAsync](https://docs.expo.io/versions/latest/sdk/imagepicker.html#expoimagepickerlaunchimagelibraryasyncoptions)

これらで、`async/await`を利用して非同期関数を定義します。

```js
  _pickImage = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      allowsEditing: true,
      aspect: [4, 3],
    });
```

* allowsEditing  
  画像/ビデオを選択した後に編集するためのUIを表示するかどうか
* aspect  
  編集時の縦横比。Androidのみ適用され、iPhoneは正方形になる

# 簡易的なPUBLISH
[Expo XDE](https://expo.io/tools#xde)を使うと、作ったアプリをウェブ上に簡易的リリースできます。`publish`を押すとしばらく経って 
`19:33:53 Published to https://exp.host/hogehoge/cameraapp` 

という風にURLが発行されます。

![screen.png](https://qiita-image-store.s3.amazonaws.com/0/87716/44c087ae-17df-2390-bea7-36d934bfa32d.png)

このURLを共有すると、[Expo Client App](https://itunes.apple.com/us/app/expo-client/id982107779?mt=8)をインストールした端末で共有できますので簡単に人に自慢でき、おー、という反応にテンションが上がります。

以上、「試してみた」風の基本的な内容で恐縮ですが、 React Nativeで出来る事の概要がざっくり伝われば幸いです。


# 参考にさせて頂きました :pray_tone1:
[React Native](https://facebook.github.io/react-native/)
[Expo](https://docs.expo.io/versions/latest/sdk/imagepicker.html)
[React Native + Expo.ioでさくっとカメラアプリを作ってみる](http://ykubot.com/2017/10/22/react-native-expo-image-picker/)
[React における State と Props の違い](https://qiita.com/kyrieleison/items/78b3295ff3f37969ab50)
[[JavaScript] 変数名が中括弧で囲まれた変数宣言](https://qiita.com/takahiro_itazuri/items/1016494c2e3b815cbe6d)
[async/await 入門（JavaScript）](https://qiita.com/soarflat/items/1a9613e023200bbebcb3)
[React Nativeのデザイン - Stylesheet/Flexbox (part1)](https://qiita.com/shohey1226/items/5185fcba7381bf4da2f2)