30
12

More than 3 years have passed since last update.

react-firebase-hooksを使ってみた(Auth Hooks編)

Last updated at Posted at 2019-12-05

はじめに

FirebaseとFirestoreをReact Hooksで使いたいと以前から思っていましたが、react-firebase-hooks v1はあまり納得がいかず、自作のcustom hooksを使っていました。その後v2が出たので、調べなければと思いつつ、半年くらい経ってしまいましたが、とうとう重い腰をあげることにします。

react-firebase-hooks

リポジトリはこちらです。

今回はAuth Hooksを試してみようと思います。

コーディング

モジュールのimport

最初に必要なモジュールをimportします。

import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";

import firebase from "firebase";
import { useAuthState } from "react-firebase-hooks/auth";

firebaseの初期化

次に、firebaseの初期化をします。

const firebaseConfig = {
  apiKey: "...",
  authDomain: "...",
  databaseURL: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "..."
};
firebase.initializeApp(firebaseConfig);

Loginコンポーネント

ログイン用のコンポーネントを作ります。

const Login = () => {
  const [email, setEmail] = useState("");
  const [pass, setPass] = useState("");
  const [error, setError] = useState(null);
  const [pending, setPending] = useState(false);
  const mounted = useRef(true);
  useEffect(() => {
    const cleanup = () => {
      mounted.current = false;
    };
    return cleanup;
  }, []);
  const onSubmit = async e => {
    e.preventDefault();
    setError(null);
    setPending(true);
    try {
      await firebase.auth().signInWithEmailAndPassword(email, pass);
    } catch (e) {
      console.log(e.message, mounted);
      if (mounted.current) setError(e);
    } finally {
      if (mounted.current) setPending(false);
    }
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          type="email"
          value={email}
          onChange={e => setEmail(e.target.value)}
          placeholder="Email..."
        />
        <input
          type="password"
          value={pass}
          onChange={e => setPass(e.target.value)}
          placeholder="Password..."
        />
        <button type="submit">Login</button>
        {pending && "Pending..."}
        {error && `Error: ${error.message}`}
      </form>
    </div>
  );
};

ちょっと複雑になりましたが、やっていることは単純です。本来は、テキストフィールドを更新したところで、エラーメッセージをクリアすべきですが、そこは省略。

Logoutコンポーネント

ログアウト用のコンポーネントを作ります。

const Logout = () => {
  const [pending, setPending] = useState(false);
  const mounted = useRef(true);
  useEffect(() => {
    const cleanup = () => {
      mounted.current = false;
    };
    return cleanup;
  }, []);
  const logout = async () => {
    setPending(true);
    await firebase.auth().signOut();
    if (mounted.current) setPending(false);
  };
  return (
    <div>
      <button type="button" onClick={logout}>
        Logout
      </button>
      {pending && "Pending..."}
    </div>
  );
};

Pending表示が短い場合はChrome Dev ToolsのNetwork TabでThrottlingをしましょう。

Appコンポーネント

最後に、全体をつなげるAppコンポーネントとReactDOMのrenderです。

const App = () => {
  const [user, initialising, error] = useAuthState(firebase.auth());
  if (initialising) {
    return <div>Initialising...</div>;
  }
  if (error) {
    return <div>Error: {error}</div>;
  }
  if (!user) {
    return <Login />;
  }
  return (
    <div>
      User: {user.email}
      <Logout />
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

今回は、ログインしたらユーザのemailを表示するだけのシンプルなものです。

CodeSandbox

完成したものがこちらです、実際に動作させるためにはforkしてfirebaseConfigを置き換える必要がありますのでご注意ください。

おわりに

今までは、onAuthStateChangedをラップした独自custom hooksを使ってましたが、それがライブラリ化されることで、多少見通しはよくなったような気はします。しかし、loginやlogoutの機能を内包するcustom hooksは提供されていないため、今回のように長いコードになってしまいました。結局、そこには独自custom hooksが必要になりそうです。

30
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
12