🐡
Next.jsとFirebase(SDK v9)authで匿名ログイン -> Googleログイン永続化のExample
要約
- Next.jsを使って、Firebase Authの認証機能を実装
- 状態管理はrecoilを使った
- アプリ起動時に匿名ログイン、Googleログインを選択後アカウント移行
- FirebaseWeb SDK v9(v8と結構違ったので最初びっくりしました)
コード
こちらです。
動作
-
アプリ起動時に匿名ログインが自動的に走る(isAnnonymusがtrue)
-
Googleログインボタン押すと、ログインフローへ
-
ログイン完了後、uidは変化せずにisAnnonymusがtrueからfalseに変化(匿名ログインの永続化)
解説
このコミット見てください!
firebaseClient.ts
import { initializeApp } from 'firebase/app'
import { getFirestore } from 'firebase/firestore/lite'
import { getAuth, GoogleAuthProvider } from 'firebase/auth'
const CLIENT_CONFIG = {
apiKey: 'XXXXX',
authDomain: 'XXXXX',
projectId: 'XXXX',
storageBucket: 'XXXXX',
messagingSenderId: 'XXXXXX',
appId: 'XXXXX',
}
const app = initializeApp(CLIENT_CONFIG)
const firebaseAuth = getAuth(app)
const db = getFirestore(app)
const googleProvider = new GoogleAuthProvider()
export { app, firebaseAuth, db, googleProvider }
_app.tsx
import '../styles/globals.css'
import { useEffect } from 'react'
import { RecoilRoot, useSetRecoilState } from 'recoil'
import { currentUserState } from '../lib/atoms/currentUser'
import { signInAnonymously, onAuthStateChanged } from 'firebase/auth'
import { firebaseAuth } from '../lib/firebase/firebaseClient'
const AppInit = () => {
const setCurrentUser = useSetRecoilState(currentUserState)
const fetchSetUser = async () => {
try {
onAuthStateChanged(firebaseAuth, async (user) => {
if (!user) {
signInAnonymously(firebaseAuth)
.then(async (e) => {
if (e.user) {
setCurrentUser({
uid: e.user.uid,
displayName: e.user.displayName,
isAnonymus: e.user.isAnonymous,
})
}
// eslint-disable-next-line no-console
})
.catch(() => {
// console.log(error)
})
} else {
setCurrentUser({
uid: user.uid,
displayName: user.displayName,
isAnonymus: user.isAnonymous,
})
}
})
} catch {
setCurrentUser(null)
}
}
useEffect(() => {
fetchSetUser()
}, [])
return null
}
function MyApp({ Component, pageProps }) {
return (
<RecoilRoot>
<AppInit />
<Component {...pageProps} />
</RecoilRoot>
)
}
export default MyApp
index.tsx
import styles from '../styles/Home.module.css'
import { useCurrentUser } from '../lib/hooks/useCurrentUser'
import { firebaseAuth, googleProvider } from '../lib/firebase/firebaseClient'
import { linkWithPopup } from 'firebase/auth'
import { currentUserState } from '../lib/atoms/currentUser'
import { useSetRecoilState } from 'recoil'
export default function Home() {
const { currentUser } = useCurrentUser()
const setCurrentUser = useSetRecoilState(currentUserState)
const loginWithGoogle = () => {
linkWithPopup(firebaseAuth.currentUser, googleProvider)
.then((result) => {
const user = result.user
setCurrentUser({
uid: user.uid,
displayName: user.displayName,
isAnonymus: user.isAnonymous,
})
})
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.catch((error) => {
// Handle Errors here.
})
}
return (
<div className={styles.container}>
<main className={styles.main}>
<button className="bg-gray-100 p-5" onClick={() => loginWithGoogle()}>
Googleログイン
</button>
<div className="w-full break-all">{JSON.stringify(currentUser)}</div>
</main>
</div>
)
}
Discussion