🔥
Next.jsとTypeScriptでFirebaseのGoogle authを実装する
※ 2021/11/05 追記
備忘録としてまとめます。
完成したもの
完成したものは下の URL においています。
Nextjs のセットアップ
yarn create next-app my-app --example with-typescript
ファイルを移動
mkdir src
mv pages src
mv components src
mkdir src/lib
あと tsconfig.json
に
tsconfig.json
"baseUrl": ".",
"paths": {
"~/*": ["./*"]
},
追加します。
Firebase で新規プロジェクトをつくる
で新規プロジェクトを作成し、
プロジェクト設定 > 全般
から API key などを .env.local
に下のようにコピーします。
※************
のところはそれぞれ対応する値に置き換えてください。
.env.local
NEXT_PUBLIC_FIREBASE_API_KEY=************
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=************
NEXT_PUBLIC_FIREBASE_DATABASE_URL=************
NEXT_PUBLIC_FIREBASE_PROJECT_ID=************
NEXT_PUBLIC_FIREBASE_STORAGE_BAKET=************
NEXT_PUBLIC_FIREBASE_MESSAGE_SENDER_ID=************
NEXT_PUBLIC_FIREBASE_APP_ID=************
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=************
それができたら
yarn add firebase
で firebase 関連のパッケージを追加
Next.js のファイルにコードを追加
つぎに、以下の Nextjs ファイルにコードを追加していきます。
src/lib/firebase.ts
import firebase from "firebase/app";
import "firebase/auth"; // If you need it
export const config = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
!firebase.apps.length ? firebase.initializeApp(config) : firebase.app();
export const auth = firebase.auth();
export const Firebase = firebase;
export const Login = () => {
const provider = new firebase.auth.GoogleAuthProvider();
firebase
.auth()
.signInWithPopup(provider)
.then(function (result: any) {
return result;
})
.catch(function (error) {
console.log(error);
const errorCode = error.code;
console.log(errorCode);
const errorMessage = error.message;
console.log(errorMessage);
});
};
// ログイン状態の検知
export const listenAuthState = (dispatch: any) => {
return firebase.auth().onAuthStateChanged(function (user) {
if (user) {
// User is signed in.
dispatch({
type: "login",
payload: {
user,
},
});
} else {
// User is signed out.
// ...
dispatch({
type: "logout",
});
}
});
};
export const firebaseUser = () => {
return firebase.auth().currentUser;
};
// Logout
export const Logout = () => {
auth.signOut().then(() => {
window.location.reload();
});
};
src/lib/AuthContext.ts
import React from "react"
const AuthContext = React.createContext({})
export default AuthContext
src/pages/_app.tsx
import React, { useReducer, useEffect } from "react";
import { AppProps } from "next/app";
import AuthContext from "~/src/lib/AuthContext";
import authReducer from "~/src/lib/authReducer.ts";
import { listenAuthState } from "~/src/lib/firebase";
function MyApp({ Component, pageProps }: AppProps) {
const [state, dispatch] = useReducer(
authReducer.reducer,
authReducer.initialState
);
useEffect(() => {
return listenAuthState(dispatch);
}, []);
return (
<AuthContext.Provider value={state}>
<Component {...pageProps} />
</AuthContext.Provider>
);
}
export default MyApp;
src/lib/authReducer.ts
const initialState = {}
const reducer = (state: any, action: any) => {
switch (action.type) {
case "login":
return action.payload.user
case "logout":
return initialState
default:
return state
}
}
export default {
initialState,
reducer,
}
最後に src/pages/index.tsx
を修正すれば完成です
src/pages/index.tsx
// import Link from "next/link";
import Layout from "../components/Layout";
import { Login, Logout, auth } from "~/src/lib/firebase";
const IndexPage = () => (
<Layout title="Home | Next.js + TypeScript Example">
<h1>Hello Next.js 👋</h1>
<div>
<button onClick={() => Login()}>ログイン</button>
<button onClick={() => Logout()}>ログアウト</button>
</div>
<div>
<pre>
{auth.currentUser
? auth.currentUser.displayName + "でログインしています"
: "ログインしていません"}
</pre>
</div>
</Layout>
);
export default IndexPage;
完成
ログインしているときはこのように
未ログイン時はこのように表示されると思います
Discussion
この記事のおかげでauthの実装をすることができました
ありがとうございます😊
一部修正タイポがあったので報告いたします。
>src/lib/firebase.ts
ありがとうございます。タイポ修正しました。