フルスタックチャンネル
サインアップサインアップ
ログインログイン
利用規約プライバシーポリシーお問い合わせ
Copyright © All rights reserved | FullStackChannel
解決済
Googleログイン直後に、自動で、ログインしたユーザー情報を取得したいです。
DRF
Next.js
React
Apple
2023/03/07 10:42

実現したいこと

Googleログイン直後に、自動で、ログインしたユーザー情報を取得したいです。

発生している問題

  • 現在、GoogleログインのsignIn()関数を実行し、Googleログインに成功しました。
  • 現在、ボタンをクリックして、ユーザー情報取得関数getUserData()関数を実行し、ユーザー情報の取得に成功しました。
  • しかし、GoogleログインのsignIn()関数を実行した直後に、自動でユーザー情報取得関数getUserData()が実行されるようにコードを書きましたが、ユーザー情報取得関数getUserData()動きません。

ソースコード

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()を使って、状態管理を行っています。

回答 6件
login
回答するにはログインが必要です
Apple
約3年前

「[...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を取得する方法は、英語を含めて、本当に少なくて大変でした。このやり方がヒントになったら幸いです。

1
はる@講師
約3年前

情報ありがとうございます。

はる@講師
約3年前

順番に処理をしたい場合は、awaitを使用して処理が終わってから、次の処理が走るようにしてあげないといけないです。

こうしないと、前の処理が終わる前に、次の処理が走って、想定した動作にならないです。

こちらイメージです。

const loginHandler = async () => {
    await signIn();
    await getUserData();
  };
はる@講師
約3年前

無事解決できて良かったです。

Apple
約3年前

自力で解決しました。
useEffect()を使って、ログイン直後、自動でユーザー情報を取得できるようにしました。

  useEffect(() => {
    if (session) {
      getUserData();
    }
  });

awaitのVSCodeでのエラー表示は、私が「await getUserData()」とするところを「await getUserData」としていたことが原因でした。失礼しました。
なぜ、awaitでは動かないのか、いまだに分かりません。
問題解決に寄り添っていただき、ありがとうございました。

1
Apple
約3年前

お返事、ありがとうございます。
VSCodeにて、二つ目の「await」の部分に、「'await' has no effect on the type of this expression.」という表示が出ていまして、やはり、動きません。

1