初めに
どもども龍ちゃんです。今回は、同期が書いた記事を補足する新しい形でTech Blogを書いていきます。
お疲れ様です。今回は以下の記事を補足する形で進めていきます。以下の記事ではTypescriptで状態管理にRecoilを採用、React-routerでルーティングを行っています。
- [React + Firebase Authentication](前編)reactプロジェクトの作成とfirebaseの初期設定
- [React + Firebase Authentication](後編)ワンクリックログイン機能とルーティングの設定
今回この記事で取り扱う内容としては以下の2点になります。
- Firebaseでログイン・ログアウト・ユーザ情報取得
- React-routerで認証許可ページを作成
もしクリティカルに困っている問題がない方は、上記のリンクを1から追っていくことをお勧めしています。一応、社内リンク以外にも参考にしたサイトをこのブログのサイトに載っているので、他のサンプルを見たい場合はそちらから参照をお願いします。
ソースだけ見れれば問題ないという方は、検証用のリポジトリを置いておきます。環境はViteで作成されています。環境変数については自分で設定をお願いします。設定方法を念のために置いておきます。[公式サンプル・参考にしたZenn](ちなみにViteのlocalでの起動コマンドはyarn devです)
クリティカルに困っている問題がある方は、今回この記事で解消するといいですね。上記で紹介している記事から解消している部分とエラーで詰まった部分について記載しておきます。
- リダイレクトした際に認可ページに入れない or 真っ白なページになる or 画面がちらつく
- エラーで「Uncaught TypeError: Cannot delete property ‘1’ of [object Array]」が出る
それでは、本題のソース解説の方に入っていきます。まず、今回の構成について解説を入れて、そこをコードに落とし込む作業に入っていきます。
構成
今回の構成としては以下の図になります。全体としてはページ3枚、ルーティング用コンポーネント2個追加となります。これとは別にReact-router用のファイルがあることは年頭に置いておいてください。
想定しているパターンとしては、以下になります。
- 認証トップページ:認証なしでも閲覧可能でログインボタンやログアウトボタンが配置
- マイページ:要認証でログインユーザの情報を表示
ルーティング用コンポーネントは、機能によって分割しています。ここは口頭よりもコードの方がわかりやすいと思うのでコードの解説を行っていきます。
事前準備
今回は、Firebaseのアプリの作成の解説入れません。なので事前準備としてFirebase Consoleでアプリを設定してKey情報を取得しておいてください。この記事を参考にFirebase SDKの追加の部分でKey情報の取得までを済ませておいてください。以下の情報に見覚えがなければ問題ありません。
const firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
projectId: "xxxxxxxxxxxxxxxxxxxxxxx",
storageBucket: "xxxxxxxxxxxxxxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
};
この情報は後で使うのでどこかにメモしておきましょう。(情報流出にだけは気を付けてください)
あとはFirebaseのパッケージも入れておきましょう。
yarn add firebase
コード解説
コードの流れとしては以下の順番で解説していきます。
- Firebaseを扱うための設定
- Recoil用ファイルの作成
- ルーティング用コンポーネントの作成
- ログイン・ログアウト処理の切り出し
- ページの作成
- React-Routerファイルの編集
ファイル構造で迷わないようにここでファイル構造について触れておきます(ディレクトリ構造といった方がかっこいいですし、迷わないんですけどね)。ファイル構造としては以下の構成になっています。ここは独学なので現在も悩み中です。
Firebaseを扱うための設定
前回の記事とビルドが「create-react-app」から「Vite」に代わっているので念のために解説を入れておきます。もしわかっている場合は読み飛ばしてもらって大丈夫です。事前準備で取得したKey情報を使用するので用意をお願いします。
ビルドでViteを採用している人、僕の環境からCloneした方は、「.env.development」というファイルを作成して以下を転記してください。ファイルの位置はルート直下です(package.jsonがあるところ)。「xxxxxxx」の中身は先ほど用意したKey情報に変更してください。
VITE_FB_APIKEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VITE_FB_AUTHDOMAIN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VITE_FB_PROJECT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VITE_FB_STORAGE_BUCKET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VITE_FB_MESSAGEING_SENDER_ID=xxxxxxxxxxxxxxxxxxxxxxx
VITE_FB_APP_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
もしビルドで「create-react-app」を採用している人は、「env.local」というファイルを作成して以下を転記してください。
REACT_APP_FIREBASE_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
REACT_APP_FIREBASE_AUTH_DOMAIN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
REACT_APP_FIREBASE_PROJECT_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
REACT_APP_FIREBASE_STORAGE_BUCKET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
REACT_APP_FIREBASE_MESSAGE_SENDER_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
REACT_APP_FIREBASE_APP_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
その他のビルドを採用している人は、おそらく最強エンジニアが近くにいると思うので「環境変数の読み込みどうすればいいか」を質問してきてください。
環境変数の設定としては以上になります。次にFirebaseをReactで扱う設定をしていきます。hooksのファイルの中で「authFirebase.ts」というファイルを作成して以下の内容を転記してください。
create-react-appをビルドで採用している場合は、「import.meta.env~~~」の部分が「process.env.~~~」に代わります。参考サイトは置いておきます。
これにて、Firebaseを扱う準備は終了しました。
Recoilファイルの作成
ここでは、Recoil用の設定を作成していきます。providerのファイル内で「firebaseStore.ts」というファイルを作成して以下の内容を転記してください。
内容について触れておきます。「authenticatedState」は認証状態をチェックするbooleanになります。「userUidState」はログインしたユーザ情報を保持するためのステートです。
ルーティング用コンポーネントの作成
ここでは、ルーティング用コンポーネントの解説・作成をしていきます。routerファイル内で「RouterAuthenticateConfig.tsx」を作成して以下の内容を転記してください。上から順番に解説を入れていきます。
「NavigationPage」はリダイレクトを扱うためのコンポーネントになります。URL直リンクで「firebase/mypage」にアクセスしてきた場合「/firebase」に戻してあげる際に使用します。コンポーネントとして切り出しているわけとしては、使いまわしが想定されるのとコンポーネントとして宣言しないとエラーメッセージが出る場合があるためです。もし使いまわしが想定される場合は「utilities」ないでコンポーネントとして切り出してあげましょう。
「RouterAuthenticatedCheck」は認証状態の監視と保存を行っています。Recoilの使い方については触れませんが、「useSetRecoilState」「useResetRecoilState」はよく使うので知らなかった場合はRecoilのサイトで復習をしましょう。ここで一番重要となるのが「useEffect」の内部になります。
「onAuthStateChanged」はFirebaseが提供している関数になります。認証状態が切り替わった場合に起動して、ログインであれば情報の取得、ログアウトであれば情報のリセットを行います。状態の切り分けには「getAuthUser:User | null」を使用しています。getAuthUserに情報があればログイン状態でなければログアウト状態といった具合に切り分けています。
ここで注意点です。Recoilでユーザの情報取得用に「userUidState」を作成しましたが、ここの型をFirebaseが提供しているType Userにしてしまえばいいじゃないかと思いませんでしたか?僕もトライしてみたのですが、うまくいかずに「Uncaught TypeError: Cannot delete property ‘1’ of [object Array]」が吐き出されました。指定の方法がまずいのか原因は不明なので、おとなしくgetAuthUserから一個一個指定して抜き出してあげましょう。
もう一点注意する点としては、変数「loading」になります。もしloadingの変数がない状態で想像される状態としては、「ログインした後でリロードをすると認証ページから追い出される」といった状態が想像されます。これは、useEffectの発動タイミングが影響しています(strickModeですね)。そのため、「onAuthStateChanged」が一度も呼ばれていないタイミングでは「loading」をfalseとしてリロード画面を表示しています。
useEffectのreturnで呼んでいるunsubscribeはイベント解除ですね。アンマウント時に監視していたonAuthStateChangedを破棄しています。
「RouterHasAuthenticated」では、Recoilで用意した「authenticatedState」を基に認証状態によってリダイレクトか表示を分岐させています。
変数名が長いですが、これにはちゃんと訳がありまして。最近お世話になっている上司の方からありがたいコードレビューをいただきまして、矯正中なわけです。ブログにまとめているので紹介しておきます。
ログイン・ログアウト処理の切り出し
ここではカスタムフックとしてログインとログアウトの処理を切り出しています。正直やる必要はないです。なんでも切り出す必要はないのですが、適度な粒度が難しいので解説のために切り出しています。方法としては公式の記事を置いておきます。hooksフォルダ内に「useFirebaseAuth.ts」ファイルを作成して以下の内容を転記してください。
解説を入れるほどでもないのですが、ファイルを作成したことでファイルのどこでも「const {signInAction, singOutAction} = useFirebaseAuth()」で処理を呼び出せるようになりました。
ページの作成
あともう少しで解説が終了します。表示するページを作成していきましょう。components/page内に「MyPage.tsx」と「FirebasePage.tsx」を作成して以下の内容を転記してください。
「MyPage.tsx」ではRecoilで情報取得を「FirebasePage.tsx」ではログイン・ログアウトのフック呼び出しをしています。
React-Routerファイルの編集
これが最後の解説です。ここでは、構成のときにお話ししたように構成していきます。
まず見てほしい部分としては、Routeのelementです。「/firebase」では「RouerAuthenticatedCheck」が「/firebase/mypage」では「RouterAuthenticated」が指定されています。このように本来表示したい情報をルートコンポーネントを介して渡しています。このように指定することで、ルーティング機能を有効にします。
また、「/firebase」のRouteで「Route index」と「Route mypage」を囲うことで、「/firebase」以下にアクセスした際に「RouterAuthenticatedCheck」が走るように構成できます。
「Outlet」と「Route index」はキーワードだけ置いておきますね。
終わりに
今回は、人の記事を加筆する形でブログを書いてみました。認証機能は構成方法がいろいろあると思います。実装が正しいかどうかは難しいトピックですよね。
セキュリティ的観点でもSocial Loginというものは良いものであると思っています。とりあえずお疲れ様でした。今回参考にしたサイトは以下になります。
また、今回はFirebaseが提供しているSDKのみを使用しましたが、React用にまとめられたフックもあるそうです。そちらの記事も載せておきますね。
ではまた!