🗣️

【Firebase Authentication×React】ログイン中かどうかで画面を分ける

2022/10/10に公開

さくっと認証機能を作りたいときには、Firebase Authenticationは本当に便利。
小規模な利用なら無料の範囲で全然利用できるし(プロジェクト数に制限はあるものの…)

Webアプリでの利用も基本的には公式ドキュメントのとおりやるだけで全然簡単だが、始めて使おうとしたときにとりあえずつっかかるのは、ログイン中かどうかで画面を出し分けようとしたときに、状態が同期的に取れないということだと思う。

getAuth().currentUser != null で分岐しようとすると、ログイン状態が取得できる前に判定が走ってしまってうまくいかないため、むりやり1秒スリープを入れたり、あるいはポーリングし続けるような方法で頑張っているコードを見かけることがある。

正しい方法としては onAuthStateChanged をオブザーブしてやるわけですが、これがいまいちReactみたいなコンポーネントに組み込みにくいというのもわかる。

個人的にはよく、こんなHooksにして使います。

export const useCurrentUser = () => {
    const [ user, setUser ] = useState<User | null>(null);

    useEffect(() => {
        const unsubscribe = onAuthStateChanged(getAuth(), user => {
            setUser(user);
        });
        return unsubscribe;

    }, []);
    
    return user;
}

使うほうはこんなイメージ。

export const ComponentForUser = () => {
    const user = useCurrentUser();

    if (user == null) {
        return <div>ログインしていません</div>
    }

    return (
        <div>
            ユーザ名:<span>{user.displayName}</span>
        </div>
    )
}

あるいはこのHooks自体をHOCっぽく使ってもいい。

export const AuthGuard = (props: { children: ReactNode }) => {
    const user = useCurrentUser();

    if (user == null) {
        return <></>
    }

    // ログイン中の場合のみ子のコンポーネントを描画する
    return <>{props.children}</>
}

親側の画面イメージ。
ログインが必要な画面のコンポーネントを <AuthGuard> でラップする。

export const Layout = () => {

    return (
        <AuthGuard>
            <SomeSecretPage />
        </AuthGuard>
    )
}

Discussion