react-nativeとサーバレスでSNSアプリをリリースした話

この記事は[Alibaba Cloud Advent Calendar 2018](https://qiita.com/advent-calendar/2018/alibabacloud)の3日目の記事です。

バックエンドがAlibaba Cloudのサーバレスサービスである**Function Compute**を使ってreact-nativeでモバイルアプリを作りました。

## スライド
この記事は[Alieaters #8](https://alibabacloud.connpass.com/event/103731/)の発表に基づいて作りました。

<iframe src="//www.slideshare.net/slideshow/embed_code/key/r9Ikxnw1N3mJc4" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/RyotaSuenaga1/alieaters8-124327965" title="Alieaters#8 アリババクラウドで サーバレス頑張って モバイルアプリを作った" target="_blank">Alieaters#8 アリババクラウドで サーバレス頑張って モバイルアプリを作った</a> </strong> from <strong><a href="https://www.slideshare.net/RyotaSuenaga1" target="_blank">Ryota Suenaga</a></strong> </div>

## 作ったもの
Soramyっていう**風景画像投稿SNS**を作りました。

<blockquote class="twitter-tweet" data-lang="en"><p lang="und" dir="ltr"><a href="https://t.co/x2g8bMxOBo">pic.twitter.com/x2g8bMxOBo</a></p>&mdash; asmsuechan (@suenaga_ryota) <a href="https://twitter.com/suenaga_ryota/status/1067220780604317696?ref_src=twsrc%5Etfw">November 27, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## 作った経緯
9月1日、突然Slackで作ろうと言ったのが始まりです。ニーズ？知らねえ。ノリと勢い。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/b21e1c02-d4be-6782-89e2-90503557e239.png)

ちなみにこの人は[研究室のHPをサーバレス、SPA、GraphQL、ChatOpsで作った](https://qiita.com/asmsuechan/items/17f168f151346ac5cf65)に出てくる**後輩くん**です。

担当はこんな感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/c5b6fe5e-48c5-8eeb-f459-dfdd1d920f79.png)

## 構成
主に以下の技術を使いました。

* **Auth0**
* **react-native**
* **Alibaba Cloud**
* **GraphQL**
* **サーバレス**

webAPIをGraphQLで書いてスマホアプリがこいつと通信するってだけです。

認証系は自分で作りたくなかったので[Auth0](https://auth0.com)に丸投げしました。繋ぎこみが結構大変でした。

そしてインフラは全部アリババクラウドのサーバレスサービスである**Function Compute**で動かしました。アリババクラウド部分の構成は以下の図のような感じになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/da592bfe-c304-4f7c-9e51-7cd2a39497b2.png)


## バックエンド
バックエンドは主にアリババクラウドのFunction Computeで作りました。

### Function Compute + RDS
[Lambda+RDSはアンチパターン](https://qiita.com/teradonburi/items/86400ea82a65699672ad)で言われているのと同じ問題がFunction Compute + RDSでも生じます。

しかし私は「このサービスに人は集まらないだろうからRDSでいいや」という相当雑な判断でRDSを使いました。どうしてもサーバレスでやりたかったらNoSQLデータベースのTableStoreを使うか、コネクション用サービスを自分で立ててそこを経由してデータのやり取りをするって手があります。

でもNoSQLでリレーション持ったデータ扱うの辛いし中間サービス作ると管理するのだるいしで、あまりスッキリ解決はしません。悲しい。

### GraphQL
APIはGraphQLで作りました。というのも、API Gatewayを使うとHTTPメソッドごとに複数の設定が必要になるからPOSTのみで事足りるGraphQLが便利だったためです。

Function ComputeでGraphQLやりたい！って方は[Function Compute + API GatewayでGraphQLのAPIを作成する](https://asmsuechan.hatenablog.com/entry/2018/08/12/130000)が参考になります。

## モバイルアプリ
**react-native**でサクッとモバイルアプリを作りました。

### react-native使ってて大変だったこと
**日本語が打てない問題**
今は解消されていますが、iOSで日本語が打てない問題がありました[Controlled TextInput broken for Chinese (and other languages) in v0.54 on iOS #18403](https://github.com/facebook/react-native/issues/18403)。

**バージョンアップが大変**
上の問題を解決するためにreact-nativeを0.56から0.57にアップデートしようとしたのですが、ビルドできなくなったので断念しました。

react-native、GoogleかAppleがメンテしてくれって感じです。どっちのOSのアップデートにも追従しなきゃいけないのって、そりゃあバグりますわ。

## 使ったreact-nativeのライブラリ
react-nativeを使うにあたってライブラリの紹介って結構役に立つみたいなので私も紹介します。

### [native-base](https://nativebase.io/)
アプリ全体としてはnative-baseを使ってレイアウトの調整をしました。以前使ったことあったしドキュメント分かりやすいしと思ったので採用しました。

### [react-native-masonry-layout](https://github.com/fengmu456/react-native-masonry-layout)
私もこの開発をしていて初めて知ったのですが、Pinterestみたいな可変高さのタイルは**masonry**レイアウトって言うらしいです。
ちなみに、もっと有名なライブラリである[react-native-masonry](https://github.com/brh55/react-native-masonry)を使おうとしたのですがレイアウトが崩れたのでこっちにしました。インタフェース的にもこっちがいいので使える人はなるべくこっちを使いましょう。

masonryレイアウトはホーム画面などで使いました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/96b6bc84-362e-8449-b9e5-bbb0d3853bba.png)

### [react-native-splash-screen](https://github.com/crazycodeboy/react-native-splash-screen)
アプリが立ち上がるときに表示されるロード画面をいい感じにしてくれるライブラリです。キャプチャが下手。
![84c5d9f2c7c54d7c8d9a0d81523ff5e4.gif](https://qiita-image-store.s3.amazonaws.com/0/131581/05c43d9c-ae75-0a86-fc5a-35beaedcb5af.gif)

### [react-navigaion](https://github.com/react-navigation/react-navigation)
画面遷移はこいつを使いました。ナビゲーションって難しいですよね。

wixが出してる[react-native-navigation](https://github.com/wix/react-native-navigation)も使ってみようとしたのですが使いこなせなかったので断念しました。

### [react-native-image-picker](https://github.com/react-community/react-native-image-picker)
react-nativeでローカルから画像を持ってこようとしたらだいたい使うライブラリです。


### [react-native-placeholder](https://github.com/mfrachet/rn-placeholder)
ロード待ちの時にグレーの領域が表示されるやつありますよね。あれです。PlaceholderとかSkeltonとか言うそうです。これがあるのとないのとではだいぶ印象が違ってきますよね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/d6db9d0b-5316-6dee-044d-9f6d23276c45.png)

### [react-native-web-headroom](https://github.com/Jekiwijaya/react-native-web-headroom)
pull-to-refreshを実現するために使いました。
![05b2a3b06561efda30ea61a77955075a.gif](https://qiita-image-store.s3.amazonaws.com/0/131581/ee82e045-a307-f896-fc6a-4d26ecc5554d.gif)
まんまではありませんがこんな感じにやって作りました。`<Spinner>`はnative-baseのコンポーネントです。

```react

<HeadroomProvider>
  <ScrollableComponent
    component={ScrollView}
    scrollEventThrottle={32}
    onScroll={this.onScroll}
    refreshControl={
      <RefreshControl refreshing={this.state.isPostFetching} onRefresh={this.onRefresh} progressViewOffset={45} />
    }
  >
    <Content>
      <View style={{ flex:1 }}>
        <View style={{flex: 1, flexGrow: 10, padding: 5}}>
          {feedContent}
          {this.state.showSpinner ? <Spinner /> : undefined}
        </View>
      </View>
    </Content>
  </ScrollableComponent>
  {scrollableHeader}
</HeadroomProvider>
```

### [react-native-i18n](https://github.com/AlexanderZaytsev/react-native-i18n)
実は国際化対応しています。英語日本語中国語。

### [react-native-elements](https://react-native-training.github.io/react-native-elements/docs/avatar.html)
`<Avatar>`などいろいろな場所で使っています。

## 費用など
開発開始が9月1日で1stリリースが**9月20日**でした。

かかっている費用はRDS代の**1700円/月**とドメイン代くらいで他は特にかかっていません。

## まとめ
Alibaba Cloudのサービス、結構ググラビリティが低い名前が付いていて検索で辛い時がたまにありました。API GatewayとかOSSとか。毎回「aliyun api gateway」とかつけなきゃいけなくてスマホで打つ時面倒だった記憶。

react-nativeでハマると結局nativeの知識が必要になって辛いので次からはreact-nativeやめて**Kotlin**にしようと思います。

自分が作ったこのアプリに今は正直あまり価値を感じていないので、価値を見出した方がいたら一緒にやりませんか。


明日はAlieatersの司会進行をしてくれている[Masaki_YK](https://qiita.com/Masaki_YK)さんです！