import { signIn, signOut, useSession } from "next-auth/client";
import Link from "next/link";
import { apiUrlPart } from "../config";
import { useContext } from "react";
import { StateContext } from "../context/StateContext";
export default function Navigation() {
const [session] = useSession();
const { userId, setUserId } = useContext(StateContext);
const getUserData = async () => {
const apiRes = await fetch(`${apiUrlPart}/api/social/login/user/`, {
method: "GET",
headers: {
Authorization: `JWT ${session.accessToken}`,
},
});
const data = await apiRes.json();
console.log(data.user);
setUserId(data.user.id);
};
const logoutHandler = async () => {
signOut(); // 実行される
setUserId(""); // 実行される
};
const loginHandler = async () => {
signIn(); // 実行される
getUserData; // 実行されない
};
return (
<header className="container flex flex-row items-center mx-auto px-5 py-14 max-w-screen-lg">
<Link href="/">
<a className="text-4xl font-bold text-white">SNS</a>
</Link>
<nav className="ml-auto">
{session && session.accessToken ? (
<>
{/* 随時、取得したユーザー情報のIdを表示 */}
userId: {userId}
<Link href="/">
<div className="inline-block bg-indigo-500 mr-8 hover:bg-indigo-600 text-white px-3 py-3 rounded cursor-pointer">
ホーム
</div>
</Link>
<Link href="/profile">
<div
className="inline-block bg-indigo-500 mr-8 hover:bg-indigo-600 text-white px-3 py-3 rounded cursor-pointer"
onClick={getUserData}
>
ユーザー情報取得
</div>
</Link>
<div
className="inline-block bg-indigo-500 mr-8 hover:bg-indigo-600 text-white px-3 py-3 rounded cursor-pointer"
onClick={logoutHandler}
>
ログアウト
</div>
</>
) : (
<>
<Link href="/">
<div className="inline-block bg-indigo-500 mr-8 hover:bg-indigo-600 text-white px-3 py-3 rounded cursor-pointer">
ホーム
</div>
</Link>
<div
className="inline-block bg-indigo-500 mr-8 hover:bg-indigo-600 text-white px-3 py-3 rounded cursor-pointer"
// Googleログイン用の関数のみを実行
// onClick={() => signIn()}
// Googleログイン用の関数とユーザー取得用の関数を実行
onClick={loginHandler}
>
ログイン
</div>
</>
)}
</nav>
</header>
);
}
「Navigation.js」ファイルにて、ログインボタンをクリックした際に、「loginHandler」関数を実行する。「loginHandler」関数では、 「signIn()」関数、「getUserData」関数を、順次、実行する。
非同期の関数を二つ並べるのは無理なのでしょうか?
ご教授お願いしたいです。
Reduxは使わず、React HooksのuseContext()を使って、状態管理を行っています。
「[...nextauth].js」ファイルの「callback」にて、アクセストークンと同じように、変数「session」に、必要なユーザー情報を入れて、持ち運ぶのが正解のようです。
「[...nextauth].js」ファイルの内容は以下の通り。
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
import axios from "axios";
import {
apiUrlPart,
GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET,
} from "../../../config";
let userId = "";
let nickName = "";
let avatar = "";
const settings = {
providers: [
Providers.Google({
clientId: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
}),
],
callbacks: {
async signIn(user, account, profile) {
if (account.provider === "google") {
const { accessToken, idToken } = account;
try {
const response = await axios.post(
`${apiUrlPart}/api/social/login/google/`,
{
access_token: accessToken,
id_token: idToken,
}
);
const { access_token } = response.data;
user.accessToken = access_token;
// ユーザー情報を取得する
const apiRes = await fetch(`${apiUrlPart}/api/social/login/user/`, {
method: "GET",
headers: {
Authorization: `JWT ${user.accessToken}`,
},
});
const data = await apiRes.json();
console.log(data.user);
// 取得したユーザー情報を変数に代入する
userId = data.user.id;
nickName = data.user.nickname;
avatar = data.user.avatar;
return true;
} catch (error) {
return false;
}
}
return false;
},
async jwt(token, user, account, profile, isNewUser) {
if (user) {
const { accessToken } = user;
token.accessToken = accessToken;
}
return token;
},
async session(session, user) {
session.accessToken = user.accessToken;
session.userId = userId;
session.nickName = nickName;
session.avatar = avatar;
console.log("session.accessToken: " + session.accessToken);
console.log("session.userId: " + session.userId);
console.log("session.nickName: " + session.nickName);
console.log("session.avatar: " + session.avatar);
return session;
},
},
};
export default (req, res) => NextAuth(req, res, settings);
「useEffect」を使った方法は、アバター写真の編集にて不具合が発生したので、やめました。
next-auth内でGoogleログイン直後に、自動でログインしたユーザーのidを取得する方法は、英語を含めて、本当に少なくて大変でした。このやり方がヒントになったら幸いです。
情報ありがとうございます。
順番に処理をしたい場合は、awaitを使用して処理が終わってから、次の処理が走るようにしてあげないといけないです。
こうしないと、前の処理が終わる前に、次の処理が走って、想定した動作にならないです。
こちらイメージです。
const loginHandler = async () => {
await signIn();
await getUserData();
};
無事解決できて良かったです。
自力で解決しました。
useEffect()を使って、ログイン直後、自動でユーザー情報を取得できるようにしました。
useEffect(() => {
if (session) {
getUserData();
}
});
awaitのVSCodeでのエラー表示は、私が「await getUserData()」とするところを「await getUserData」としていたことが原因でした。失礼しました。
なぜ、awaitでは動かないのか、いまだに分かりません。
問題解決に寄り添っていただき、ありがとうございました。
お返事、ありがとうございます。
VSCodeにて、二つ目の「await」の部分に、「'await' has no effect on the type of this expression.」という表示が出ていまして、やはり、動きません。