[React Native + Expo + Firebase] シンプルなログインフォーム（Redux使用なし）

React Nativeとfirebaseを連携したいと考えており
ひとまずログインフォームを実装してみました。
（注）あくまでも自分のコードメモです。

こちらの記事を参考にしています。
[React NativeとFirebaseを使って、iosアプリのログインフォーム機能を作ってみた](https://rara-world.com/react-native-login-firebase/)

# 機能
firebaseのAuthentication連動
○アカウントが被ってなければ登録してログイン
○登録アカウントで入力すればログイン
※スタイルシートはとりあえず空にしています

簡易的ではあるがReactNativeとfirebaseでログイン機能を実装できました。
記事では素のReactNativeで動かしていますが、[Expo](https://expo.io/)を利用しても動きました。

※現在ではファンクションコンポーネントが公式でも推奨されていますが、
記事ではクラスコンポーネントで書かれているのでひとまずそれにならっています。
cf.ファンクションコンポーネントとクラスコンポーネント参考記事
[[React Native + Expo] News表示アプリを作成[part1] Hooks対応](https://qiita.com/dai_designing/items/0cdba2113aca2cf8baf4)

# 手順

プロジェクト構築後、firebaseのモジュールを追加

```console
$ npm install --save firebase
```

```jsx:components/LoginForm.js
import React, { Component } from 'react';
import { View, TouchableOpacity, Text, TextInput, ActivityIndicator } from 'react-native';
import firebase from 'firebase';
 
class LoginForm extends Component {
  state = { email: '', password: '', error: '', loading: false};
 
  onButtonPress() {
    const { email, password } = this.state;
    this.setState({error: '', loading: true});
 
    firebase.auth().signInWithEmailAndPassword(email, password)
      .then((this.onLoginSuccess.bind(this)))
      .catch(() => {
        firebase.auth().createUserWithEmailAndPassword(email, password)
          .then((this.onLoginSuccess.bind(this)))
          .catch((this.onLoginFail.bind(this)));
      });
  }
 
  onLoginSuccess() {
    this.setState({
      email: '',
      password: '',
      loading: false,
      error: ''
    });
  }
 
  onLoginFail() {
    this.setState({
      loading: false,
      error: 'Authentication Failed'
    });
  }
 
  loadSpinner() {
    if (this.state.loading) {
      return <ActivityIndicator size="small" />
    }
 
    return (
      <TouchableOpacity onPress={this.onButtonPress.bind(this)} style={styles.buttonStyle}>
        <Text>
          新規登録 or ログイン
        </Text>
      </TouchableOpacity>
    )
  }
 
  render() {
    return (
      <View>
        <View>
          <TextInput
              placeholder="user@gmail.com"
              autoCorrect={false}
              value={this.state.email}
              onChangeText={email => this.setState({ email })}
            />
        </View>
        <View style={styles.wrap}>
          <TextInput
              secureTextEntry
              placeholder="password"
              autoCorrect={false}
              value={this.state.password}
              onChangeText={password => this.setState({ password })}
            />
        </View>
 
        <View style={styles.wrap}>
          {this.loadSpinner()}
        </View>
      </View>
    )
  }
}
 
const styles = {
  // スタイルを記述
}
 
export default LoginForm;
```

```jsx:App.js
import React, { Component } from 'react';
import {View, Text, TouchableOpacity, SafeAreaView} from 'react-native';
import firebase from 'firebase';
import LoginForm from './components/LoginForm';
 
class App extends Component {
  state = { loggedIn: null };
 
  componentDidMount() {
    const firebaseConfig = {
      // 各自生成された値を入れる
      apiKey: "Your_code",
      authDomain: "Your_code",
      databaseURL: "Your_code",
      projectId: "Your_code",
      storageBucket: "Your_code",
      messagingSenderId: "Your_code",
      appId: "Your_code"
    }
    if (!firebase.apps.length) { // これをいれないとエラーになったのでいれてます。
      firebase.initializeApp(firebaseConfig);
    }
 
    firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        this.setState({ loggedIn: true });
      } else {
        this.setState({ loggedIn: false });
      }
    });
  }
 
  renderForm() {
    if (this.state.loggedIn) {
      return(
        <View style={styles.wrap}>
          <TouchableOpacity onPress={() => firebase.auth().signOut()} style={styles.buttonStyle}>
            <Text style={styles.textStyle}>ログアウト</Text>
          </TouchableOpacity>
        </View>
      )
    } else {
      return(<LoginForm />)
    }
  }
 
  render() {
    return (
      <SafeAreaView>
        <View>
          <Text>{this.state.loggedIn ? "ログイン中です" : "ログインして下さい"}</Text>
        </View>
        {this.renderForm()}
      </SafeAreaView>
    )
  }
}
 
const styles = {
  // スタイルを記述
}

export default App;
```