react-native と firebase で画像の登録、表示を行う

# やりたいこと
- 画像のアップロード
 - モバイル端末上のギャラリーから画像を選択する
 - firebaseのstoreに登録する
- ダウンロード
 - firebaseのstoreから画像を取得する
 - モバイル端末上に取得した画像を表示する 


## 環境
- react-native
- expo
- expo-image-picker を利用
- FireStore

> 参考　公式ドキュメント
> https://docs.expo.io/versions/latest/sdk/imagepicker/

## 手順
- imagepickerをインストール

```
expo install expo-image-picker
```

- 以下をインポートする

```javascript:app.js
import Constants from 'expo-constants';
import * as ImagePicker from 'expo-image-picker';
import * as Permissions from 'expo-permissions';
```

- レイアウト
 - 画像登録ボタン
 - 登録した画像を表示するビューを設置

```
<Button title="写真を選択" onPress={this._pickImage} />
{image && <Image source={{ uri: this.state.image}} style={ styles.image} />}
```

- 画像登録の実行ボタン
 - `ImagePicker.launchImageLibraryAsync` で端末ライブラリを開く
 - 選択を行うとresultに結果が戻る
 - result.uriに端末内の選択した画像のuriが入っている。それをstateに設定する
 - そうすると、先ほどのレイアウトの `{image && <Image source={{ uri: this.state.image}} style={ styles.image} />}` のsoruceにimageのuriが設定されるため、選択した画像が表示される

```
// 写真選択ボタンの処理
 _pickImage = async () =>{
   try{
     let result = await ImagePicker.launchImageLibraryAsync({
       mediaTypes: ImagePicker.MediaTypeOptions.All,
       allowsEditing: true,
       aspect: [4,3],
       quality:  1,
     });
     if (!result.cancelled) {
       this.setState({image:result.uri});
     }

     console.log(result);
   } catch(E){
     console.log(E);
   }
 };
```

## Firebaseへアップロードする

- result.uriをblobに変換し、アップロードできるようにする

```
const localUri = await fetch(result.uri);
//blobを取得
const localBlob = await localUri.blob();
// stateに設定　（submit時にstateごと登録処理に送るため、stateに設定して巻き込んでアップロードする）
this.setState({blobImage:localBlob}); <=

```

- 以上を写真選択ボタンのアクションに追加すると以下のようになる


```
// 写真選択ボタンの処理
 _pickImage = async () =>{
   try{
     let result = await ImagePicker.launchImageLibraryAsync({
       mediaTypes: ImagePicker.MediaTypeOptions.All,
       allowsEditing: true,
       aspect: [4,3],
       quality:  1,
     });

     //撮影された（ローカルの）写真を取得 
     const localUri = await fetch(result.uri); <=
     //blobを取得
     const localBlob = await localUri.blob();  <=

     if (!result.cancelled) {
       this.setState({image:result.uri});
       this.setState({blobImage:localBlob}); <=
     }

     console.log(result);
   } catch(E){
     console.log(E);
   }
 };
```

- アップロード
 - referenceを作成する
 - パスとファイル名で参照先の箱を作り、そこに
 - `var mountainsRef = storageRef.child('images/testData.jpg');` imagesフォルダ以下にファイルが作成される `storageRef.child(`prifileImg/${user.uid}.jpg`); ` のように変数名にすればファイル名を可変とできる

```
ストレージ全体の参照を取得する
var storageRef = firebase.storage().ref();
保存先の参照：そのchildの参照を作成・取得する　フォルダ名/ファイル名.拡張子
var mountainsRef = storageRef.child('images/testData.jpg');


var blobImage = newToko.blobImage // 投稿画像のblobデータ
// アップロード実施
blobのデータを、保存先の参照にputする
mountainsRef.put(blobImage).then(function(snapshot) {
  console.log("FIRE STORE SUCCESS");
});
```

- 画面表示
 - referenceを取得する
 - そのreferenceを取得できるuriを `getDownloadURL()`で取得する
 - ここで取得できたurlは、ブラウザに入れると普通に表示ができる状態になっている。それを画面のimageタグのsourceに設定すればいい
 - 設定先は、先ほどレイアウトで用意した `{image && <Image source={{ uri: this.state.image}}` ここに表示するのがゴール
 - なので、コンストラクタで this.state.imageに設定できればいい
 - Imageタグの sourceは、rulの場合は、{uri: URLの文字列} を設定する必要がある。ローカルの時と書き方が若干異なる

```
getTokoImage =  (name) => {

    return new Promise((resolve) => {
      var storage = firebase.storage();
      var storageRef = storage.ref();
      var spaceRef = storageRef.child(`images/${name}.jpg`);
      spaceRef.getDownloadURL().then(function(url){
        console.log("ファイルURLを取得")
        console.log(url)
        resolve(url);
      }).catch(function(error) {
        // Handle any errors
        console.log("getTokoImage 画像を取得する");
        console.log(error);
      });
    });
  };
```


> 参考
> https://qiita.com/zaburo/items/0e014401e55c53395ed2
> ->しかしfirestoreにアップロードしている

> 多分正しくはStoreageにアップロードするべき
> https://qiita.com/mammothryousuke/items/68495eedb97ab954c2d8

> ユースケースが似ている
> ・ImagePickerを使い画像を取得
> ・Firebaseへアップロード
> https://qiita.com/zaburo/items/729f145735ecdc5c660c#firebase