React Native – Firebaseでユーザ作成を実装する

Google買収後、Firebaseのドキュメントもマテリアルデザインになりいい感じです。 Firebaseは、RNがでてきてすぐに対応したBaasの一つです。途中で、SDKが使えなくなり、古いバージョンで使うみたいなハックがあったように記憶しています。今は、問題なく動く(はず)です。

今回は、ちゃんと動くどうかを確かめる上でもユーザ作成あたりをさくっと実装してみます。

Firebaseのサイトに行き、アカウントを作成し、プロジェクトを作成して、”ウェブアプリにFirebaseを追加”をクリックしましょう。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-27-13-31-30

すると、下記のようなAPIキー情報もろもろが出てくるのでメモっておきます。

<script src="https://www.gstatic.com/firebasejs/3.6.1/firebase.js"></script>
<script>
  // Initialize Firebase
  var config = {
    apiKey: "YOURS",
    authDomain: "YOURS",
    databaseURL: "YOURS",
    storageBucket: "YOURS",
    messagingSenderId: "YOURS"
  };
  firebase.initializeApp(config);
</script>

忘れずにEmail認証をenableしておきましょう。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-27-13-46-03

React Nativeプロジェクトに追加するには、

1. Firebaseモジュールのインストール

$ yarn add firebase

早い噂のyarnを使ってますが、npm install firebase --saveと同義。

2. 初期化

この手の外部サービスは、app/utils/Firebase.jsのようにutils以下に入れるのが私の流儀です。

import * as firebase from 'firebase';

const config = {
  apiKey: "YOURS",
  authDomain: "YOURS",
  databaseURL: "YOURS",
  storageBucket: "YOURS",
  messagingSenderId: "YOURS"
};

module.exports = firebase.initializeApp(config);

3. 読み込んで使用する

今回は利用できるかのテストなので、componentDidMountにハードコードしてますが、ちゃんと使うにはテキストフィードを用意して、emailとパスワードを取得すれば良いと思います。

import firebase from './app/utils/Firebase';

export default class Kagami extends Component {

componentDidMount(){
let email = `test${new Date().getTime()}@test.com`;
let password = "hogehoge";

firebase.auth().createUserWithEmailAndPassword(email, password)
.catch(function(error) {
  // Handle Errors here.
  var errorCode = error.code;
  var errorMessage = error.message;
  if (errorCode == 'auth/weak-password') {
    alert('The password is too weak.');
  } else {
    alert(errorMessage);
  }
  console.log(error);
});
}

これをreloadすると、下記のようにユーザが作成されたのがわかると思います。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-27-13-44-23

Firebaseあっさり使えましたね。APIもParseと似ているので楽に使えそうです。

grip-dotted-icon for sortable list

I have a sortable list and would like users to notice that it’s sortable. I’ve researched a bit and found that grip dotted icon is for that. but as I can’t find the icon, so I made it. Please feel free to download the below with saving images.

grip-dotted-icon2x

grip-dotted-icon

React NativeでMarkdownを描写する

MarkdownのテキストをReact Native側で表示したいケースが出てきました。 リサーチすると一番最初に出てきたのがreact-native-markdownというモジュールです。少し触っていみると、最近のReact Nativeにキャッチアップしてないし、Markdown文法がWIP(Work In Progress)のステータスがあって実際の使用は難しそうでした。

リサーチを続けると、その次に出てきたのがreact-native-showdownというモジュールです。なんとWebviewを使ってMarkdownを描写してしまう代物です。これなら、いけそうな気がしたので導入を決めました。

$ npm install --save react-native-showdown

でサクッとイントールして、ドキュメント通りに使用します。

import React, { Component } from 'react';
import Markdown from 'react-native-showdown';

let Task = React.createClass({
  render() {
    const { task } = this.props;
    let markdownText = `#${task.title} \n\n${task.description}`;
    return (
       <Markdown body={ markdownText } pureCSS={pureCss} style= />
    );
  }
});

const pureCss = `
*{
  color: #333;
  font-family: "游ゴシック", YuGothic, "ヒラギノ角ゴ Pro", "Hiragino Kaku Gothic Pro", "メイリオ", "Meiryo", sans-serif;
}
`
export default Task;

ポイントはpureCSSを差し込むところですね。ES6のTemplate Stringはヒアドキュメントっぽくかけるので便利です。細かい調整はここでできるとおもいます。

Webviewを使うので、Reactっぽさはないですが描写限定で使うには非常に便利だと思います。

React Nativeにおけるローカルデータベースの考察

前回の同期の話を考えたときに、どうのようにクライアントのローカルにデータを保存するのかという問題が出てきます。

私が調べた限り、その方法は下記のようになります。

  1. ReduxのStoreで管理 – on Memory
  2. AsyncStorageを直接扱う – on Storage
  3. AsyncStorageのラッパー(react-native-store)を使う – on Storage
  4. Native(sqlite)のデータベース(react-native-sqlite-storage)を使う – on Memory
  5. Javascript database(NeDB - react-native-local-mongodb)を使う – on Memory

当たり前ですが、on Memroyは超高速ですが、容量を気にする必要があります。

1. ReduxのStoreで管理

ReduxのStoreをredux-persistなどを使いAsyncStorageにダンプすること前提です。 いい意味でも悪い意味でも自分で管理する必要が出てきます。具体的には、

  • Storeに保存するデータの構造を自前で考える必要がある
  • データを取り出すFind、整列のsortのようなメソッドを自前で作る必要がある。
  • つまり、自分でデータ構造を変えたときに、すべて書きなおすことになり修羅の道。

データ量が少なく単純な構造のときはReduxのStoreで管理しても問題ないでしょう。

2. AsyncStorageを直接扱う

オフィシャルのDocumentでも直に使うのは推奨されてません。

It is recommended that you use an abstraction on top of AsyncStorage instead of AsyncStorage directly for anything more than light usage since it operates globally.

問題点は “ReduxのStoreで管理”と同様に自前で作ることですが、それに増してStorageを扱うので処理が遅いことです。この方法にすることは基本的にないでしょう。

3. AsyncStorageのラッパーを使う

react-native-store以外にもいくつか同じようなモジュールを見かけました。Findのような関数が付属するので自前でメソッドを書く必要がありません。唯一の欠点は、速度だと思います。react-native-storeのgithub issueでもperformanceが問題になっていました。データ量が増えるとパフォーマンス的に結構厳しそうです。ただAsyncStorageのAPIをプラットフォームが提供すれば、どこでも使えることは選択する上で大事なポイントです。

4. Native(sqlite)のデータベースを使う

iOSやAndroidはsqliteのデータベースが付属しています。このsqliteをブリッジするモジュールを使います。sqliteはメモリ上で動くので高速ですし、メソッド等すべてネイティブですし、最速だと思います。 調べてみると、react-native-sqlite-storageというものがあり、CordovaのCordova-sqlite-storageのReact Nativeポートです。これは、iOSとAndroid両方同じAPIでSQLiteを叩けるものです。

Nativeコードのラッパーなので、将来、react-native-macosやreact-native-web、もしくは他プラットフォームが出てきたときに、コードの再利用が他のプラットフォームでできなくなってしまい、その場でreact-native-sqlite-storageのプラットフォームサポートを待つか自分で抽象クラスみたいなものを実装しなければいけないかもしれません。

プラットフォームのターゲットが決まっている場合は、これを選択すべきでしょう。Nativeの利点(メモリ管理など)を思う存分享受できるでしょう。

5. Javascript databaseを使う

nodeの世界には、javascriptで実装されたdatabaseというものがあります。例えば、MongoDBの簡略版のNeDBです。React Nativeにはreact-native-local-mongodbというNodeモジュールからポートされたモジュールがあります。On Memoryで動き、AsyncStorageにPersistすることもできます。Redisみたなものと想像すれば良いでしょうか。逐次AsyncStorageに書き出すのではなく、あるタイミングで書き出します。したがって、データを失う可能性がないとは言えません。

流用性と速度を気にしている場合は選択肢に入ると思いますが、データロスを気にするアプリやメモリの量を気にする場合は避けた方がいいかもしれせん。

最後に

用途によって使い分けましょう:)