본문 바로가기
source-code/Next JS

server action으로 cookie 설정 시, server component reload 버그

by mattew4483 2024. 11. 15.
728x90
반응형

Backgrounds

회원가입 후, 백엔드에서 반환한 access, refresh 토큰을 cookie에 저장해야 했습니다.

// SignUpForm
const SignUpForm = () => {
  const handleSubmit = async () => {
    try {
      // 회원가입 성공 시 AT, RT 반환
      const { accessToken, refreshToken } = await signUpApi(form);
      
      setAuthCookies(accessToken, refreshToken)
      
      router.replace("/")
    } catch (e) {
      setErrors(e);
    }
  };
  return <form onSubmit={handleSubmit} >(...)</form>
}

 

위 코드에서처럼, 회원가입 Form 제출 시 회원가입 요청(signUpApi)을 보내고

setAuthCookies 함수를 통해 반환받은 access, refresh 토큰을 cookie에 저장했습니다.

그 후 메인 페이지로 이동(router.replace)해 정상적으로 서비스를 이용할 수 있게 했습니다.

 

// utils/auth-token.ts

"use server";

import { cookies } from "next/headers";
import { AuthKeyName } from "@/shared/constant";

export async function setAuthCookies(
  accessToken: string,
  refreshToken: string
) {
  cookies().set('access-token', accessToken, options)
  cookies().set('refresh-token', refreshToken, options)
  return;
}

 

setAuthCookies 함수는 서버 액션(use server 지시어 사용)으로 작성했고,

next.js에서 제공하는 cookies API를 통해 cookie에 인증 관련 토큰을 저장할 수 있도록 했습니다.

 

Problems

위 코드들은 코드상으로도 아무런 문제가 없어 보이고, 개발 환경에서도 정상적으로 동작합니다.

 

하지만 해당 프로덕션에서 직접 회원가입을 테스트해본 결과...

router로 이동한 페이지의 서버 컴포넌트가 2~3번 정도 reload 되는 현상이 있음을 발견했습니다.

// page.ts

export const page = async () => {
    // 서버에서 여러번 실행 => 복수개 워크스페이스 생성!?
    const workspace = await getOrCreateWorkspaceApi()
    (...)
}

 

이 때 메인 페이지(서버 컴포넌트)에는 서버로부터 워크스페이스를 조회하고, 존재하지 않을 경우 생성하는 함수가 존재했고,

이로 인해, 회원가입 후 메인 페이지 접근 시 워크스페이스가 복수개 생성되어 버리는 문제가 연이어 발생했습니다.

 

Cause

이런 저런 테스트 결과 내부적인 로직 문제는 아닌 것 같아, 관련된 이슈를 검색했습니다.

https://www.reddit.com/r/nextjs/comments/1d0sr7o/double_rerendering_of_server_component_using/?rdt=51913

 

From the nextjs community on Reddit: Double re-rendering of server component using server actions

Explore this post and more from the nextjs community

www.reddit.com

 

https://github.com/vercel/next.js/issues/50163

 

Setting Cookies Via Server Action Reloads Entire App · Issue #50163 · vercel/next.js

Verify canary release I verified that the issue exists in the latest Next.js canary release Provide environment information Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Ver...

github.com

아하...

next.js 14 이상 버전에서 서버 액션을 통한 쿠키 설정 시, 의도하지 않은 페이지 리렌더링이 발생하는 이슈가 존재함을 확인할 수 있었습니다. 

Solutions

https://nextjs.org/docs/pages/building-your-application/routing/api-routes

 

Routing: API Routes | Next.js

Next.js supports API Routes, which allow you to build your API without leaving your Next.js app. Learn how it works here.

nextjs.org

api route를 통해 cookie를 설정하는 방식으로 문제를 우회할 수 있었습니다.

 

// api/auth/set-token

import { NextResponse } from "next/server";
import { setAuthCookies } from "@/utils/auth-token";

export async function POST(request: Request) {
  try {
    // 클라이언트에서 전달된 데이터 추출
    const { accessToken, refreshToken } = await request.json();

    // 쿠키에 토큰 저장하는 함수 호출
    setAuthCookies(accessToken, refreshToken);

    // 성공적인 응답 반환
    return NextResponse.json({ success: true });
  } catch (error) {
    return NextResponse.json(
      { success: false, message: "Failed to set tokens" },
      { status: 500 }
    );
  }
}

 

위와 같이 auth token을 cookie에 저장하는 api route를 생성한 후

 

// SignUpForm
const SignUpForm = () => {
  const handleSubmit = async () => {
    try {
      // 회원가입 성공 시 AT, RT 반환
      const { accessToken, refreshToken } = await signUpApi(form);
      
      // api route를 통한 cookie 설정
      await fetch("/api/auth/set-token", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ accessToken, refreshToken }),
      });
      
      router.replace("/");
    } catch (e) {
      setErrors(e);
    }
  };
  return <form onSubmit={handleSubmit} >(...)</form>
}

 

form 제출 시 해당 api로 fetch 요청을 보내, 의도대로 cookie가 설정될 수 있도록 했습니다.

 

728x90
반응형