• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    해결됨

로그인을 서버액션으로 구현해봤는데 궁금한게 있습니다.

24.05.04 17:08 작성 조회수 84

0

로그인을 클라이언트 컴포넌트에서 서버액션을 통해 구현해봤는데, 궁금한게 생겨서 질문 드립니다.

로그인 모달의 코드입니다.

 

"use client";

import style from "@/app/(beforelogin)/_component/login.module.css";
import { ChangeEventHandler, FormEventHandler, useState } from "react";
import { redirect, useRouter } from "next/navigation";
import { signIn } from "next-auth/react";
import { useFormState, useFormStatus } from "react-dom";
import onSubmit from "../_lib/signin";
import BackButton from "./BackButton";

function showMessage(messasge: string | null | undefined) {
  if (messasge === "no_id") {
    return "아이디를 입력하세요.";
  }
  if (messasge === "no_password") {
    return "비밀번호를 입력하세요.";
  }
  return "";
}

export default function LoginModal() {
  const [state, formAction] = useFormState(onSubmit, { message: null });
  const { pending } = useFormStatus();

  return (
    <div className={style.modalBackground}>
      <div className={style.modal}>
        <div className={style.modalHeader}>
          <BackButton />
          <div>로그인하세요.</div>
        </div>
        <form action={formAction}>
          <div className={style.modalBody}>
            <div className={style.inputDiv}>
              <label className={style.inputLabel} htmlFor="id">
                아이디
              </label>
              <input
                id="id"
                name="id"
                className={style.input}
                type="text"
                placeholder=""
              />
            </div>
            <div className={style.inputDiv}>
              <label className={style.inputLabel} htmlFor="password">
                비밀번호
              </label>
              <input
                id="password"
                name="password"
                className={style.input}
                type="password"
                placeholder=""
              />
            </div>
          </div>
          <div className={style.message}>{showMessage(state?.message)}</div>
          <div className={style.modalFooter}>
            <button className={style.actionButton} disabled={pending}>
              로그인하기
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

아래는 signin.ts 의 코드입니다.

"use server";

import { redirect } from "next/navigation";
import { signIn } from "@/auth";

const onSubmit = async (prevState: any, formData: FormData) => {
  if (!formData.get("id") || !(formData.get("id") as string)?.trim()) {
    return { message: "no_id" };
  }
  if (
    !formData.get("password") ||
    !(formData.get("password") as string)?.trim()
  ) {
    return { message: "no_password" };
  }

  let shouldRedirect = false;
  try {
    const response = await signIn("credentials", {
      username: formData.get("id"),
      password: formData.get("password"),
      redirect: false,
    });

    console.log(response.status, "1");
    console.log(response, "2");
    shouldRedirect = true;
  } catch (err) {
    console.error(err);
    return { message: null };
  }

  if (shouldRedirect) {
    redirect("/home"); // try/catch문 안에서 X
  }
};

export default onSubmit;

이렇게 했을 때에, 콘솔이

이렇게 찍힙니다.
1. response가 http://localhost:3000/i/flow/login

이렇게 날라오고, status는 그에 따라 undefined 입니다.

응답이 이렇게 오면 response에 따른 status를 모르는데 에러처리를 어떻게 해야하나요 ??

 

  1. 아래는 회원가입을 똑같이 서버액션으로 구현했을때에,

signup.ts의 코드입니다.

"use server";

import { redirect } from "next/navigation";
import { signIn } from "@/auth";

const onSubmit = async (prevState: any, formData: FormData) => {
  if (!formData.get("id") || !(formData.get("id") as string)?.trim()) {
    return { message: "no_id" };
  }
  if (!formData.get("name") || !(formData.get("name") as string)?.trim()) {
    return { message: "no_name" };
  }
  if (
    !formData.get("password") ||
    !(formData.get("password") as string)?.trim()
  ) {
    return { message: "no_password" };
  }
  if (!formData.get("image")) {
    return { message: "no_image" };
  }
  let shouldRedirect = false;
  try {
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_BASE_URL}/api/users`,
      {
        method: "post",
        body: formData,
        credentials: "include",
      }
    );
    console.log(response.status, "1");
    if (response.status === 403) {
      return { message: "user_exists" };
    }
    console.log(await response.json(), "2");
    console.log(response, "3");
    shouldRedirect = true;
    /*await signIn("credentials", {
      username: formData.get("id"),
      password: formData.get("password"),
      redirect: false,
    });*/
  } catch (err) {
    console.error(err);
    return { message: null };
  }

  if (shouldRedirect) {
    redirect("/home"); // try/catch문 안에서 X
  }
};

export default onSubmit;

이 때에, console.log 의 결과입니다.
response 응답 객체에서 await response.json()을 취했는데, OK로 나오는 이유가 궁금합니다.

 

  1. 로그인 구현에서

    redirect를 false로 하면 client측에서 라우팅하는 것이고, true로 하면 서버쪽에서 리다이렉트 하는 것이라고 알고 있습니다.
    그런데 서버 액션으로 api 호출을 하는 것인데,
    redirect를 false로 하고 아래 redirect를 해주어도 redirect가 되는 것인지 궁금합니다.
    그리고 redirect를 true로 하면
    이렇게 에러가 떠버립니다.
    서버액션으로 리다이렉트 시켜주는 것이라 생각해서 true옵션을 주었는데 에러가 왜 뜨는지 궁금합니다.
    바쁘실텐데 많은 질문 죄송합니다 ㅜㅜ

답변 1

답변을 작성해보세요.

0

https://next-auth.js.org/getting-started/client#using-the-redirect-false-option

에러는 response 객체 안에 들어있습니다.

redirect: true 옵션은 NextAuth 설정 시에 적은 주소로 리다이렉트하는 옵션입니다. 저희는 그걸 사용하지 않고 리다이렉트를 수동으로 진행하고 있는 것입니다.