React のカスタムフックでロジックを共有する
React のカスタムフックを使って、複数のコンポーネントでロジックを共有する。
今まで作っていた物の仕様変更に伴い、複数のコンポーネントでロジックを共有するためにカスタムフックを使ってみた。
GitLab に完成品を置いた。
元の仕様
- ページは「記事一覧」「ログイン」「記事投稿」の 3 画面
- 「記事投稿」画面はログイン済の状態でしか表示できない
新仕様
- ページは「記事一覧」「ログイン」の 2 画面
- 「ログイン」画面は未ログイン状態でしか表示できない
- 「記事一覧」画面をログイン済の状態で閲覧した場合、記事投稿フォームが画面上部に表示される
共有するロジックは
- ユーザーが現在ログインしているかどうかの判定
で、これを下記の 2 か所で共有する。
- 「ログイン」画面は未ログイン状態でしか表示できない
- 「記事一覧」画面をログイン済の状態で閲覧した場合、記事投稿フォームが画面上部に表示される
カスタムフック作成
元々ログインしているかどうかの判定をどのように実装していたかは
Firebase Authentication で認証状態になったときだけ閲覧できるページを作る
という記事に書いた。
上記記事の認証状態判定を useAuth というカスタムフックに切り出す。
src/hooks/Auth/useAuth.js
import { useState, useEffect } from "react";
import { app } from '../../config/firebase';
import { getAuth, onAuthStateChanged } from "firebase/auth";
export const useAuth = () => {
const [signinCheck, setSigninCheck] = useState({ signinCheck: false, signedIn: false });
useEffect(() => {
const auth = getAuth();
var unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setSigninCheck({ signinCheck: true, signedIn: true });
} else {
setSigninCheck({ signinCheck: true, signedIn: false });
}
})
unsubscribe();
}, []);
return [signinCheck];
};
『「ログイン」画面は未ログイン状態でしか表示できない』の実装
ログインしていたら「記事一覧」画面にリダイレクトし、ログインしていなかったら呼び出されたパスを表示するコンポーネントを作成する。
src/NotAuth.jsx
import React from 'react';
import { Redirect } from 'react-router-dom';
import { useAuth } from "./hooks/Auth/useAuth";
function NotAuth(props) {
const [signinCheck] = useAuth();
if (!signinCheck.signinCheck) {
return (
<div>Loading...</div>
);
}
if (signinCheck.signedIn) {
return <Redirect to="/" />
} else {
return props.children;
}
}
export default NotAuth;
これを使ってルーティングを行う。NotAuth コンポーネントで囲んだ部分がログインしていない場合だけ表示するページになる。
src/App.js
|
|
『「記事一覧」画面をログイン済の状態で閲覧した場合、記事投稿フォームが画面上部に表示される』の実装
記事投稿フォームのコンポーネントで、ログイン済みの場合のみ記事投稿フォームを返すようにする。
src/Input.jsx
|
|
あとは記事一覧に上記コンポーネントを埋め込めば完成。
以上