[Next-auth] Objects are not valid as a React child (found: object with keys {redirect}) 오류 해결

강 수정·2024년 1월 26일
0


❌ 오류 발생


❌ Unhandled Runtime Error
Error: Objects are not valid as a React child (found: object with keys {redirect}). If you meant to render a collection of children, use an array instead.

오류가 발생한 코드입니다.

// app/api/auth/signin/page.tsx

import SocialLoginBtn from '@/app/components/SocialLoginBtn';
import { authOptions } from '../[...nextauth]/route';
import { getServerSession } from 'next-auth';
import { getProviders } from 'next-auth/react';

export default async function SignInPage() {
  const session = await getServerSession(authOptions);
  if (session) {
    return { redirect: { destination: '/' } };
  }
  const providers = (await getProviders()) ?? {};
  return (
    <section>
      <div>
        <h2>Sign-in</h2>
        <p>지금 바로 로그인하세요!</p>
      </div>
      <SocialLoginBtn providers={providers} />
    </section>
  );
}
// src/app/components/SocialLoginBtn.tsx
'use client';

import { ClientSafeProvider, signIn } from 'next-auth/react';

type Props = {
  providers: Record<string, ClientSafeProvider>;
};

export default function SocialLoginBtn({ providers }: Props) {
  return (
    <div>
      {Object.values(providers).map((provider) => (
        <button
          key={provider.name}
          onClick={() => signIn(provider.id)}
          >
          {provider.name}로 로그인
        </button>
      ))}
    </div>
  );
}

👿 문제 상황


next-auth sign-up 페이지를 custom page로 바꾸기 위해 코드를 리펙토링하던 중 위 사진과 같은 오류가 발생했습니다. next-auth의 signIn 함수가 실행되면 url이 callbackUrl 파라미터를 전달받은 후 Objects are not valid as a React child (found: object with keys {redirect}) 런타임 오류가 발생합니다.

하지만, url을 임의로 메인 페이지인 localhost:3000경로로 이동하면 로그인이 잘 되어있는 것을 확인할 수 있었습니다.



🧐 원인 분석


1. 첫 번째 시도: providers을 렌더링할 때 생긴 문제일까?

오류메시지는 Objects는 리액트 컴포넌트에 직접적으로 렌더링될 수 없다고 합니다. 혹시 providersmap함수로 처리하는 과정에서 렌더링시 생긴 문제는 아닐까 생각했습니다.

providers의 생김새를 보려고 콘솔을 한 번 찍어봤습니다.

// src/app/components/SocialLoginBtn.tsx
'use client';

import { ClientSafeProvider, signIn } from 'next-auth/react';

type Props = {
  providers: Record<string, ClientSafeProvider>;
};

export default function SocialLoginBtn({ providers }: Props) {
  console.log(providers);
}

providers의 구조는 github, kakao, naver 세 가지의 provider을 가진 객체인 것을 확인했습니다.


map함수의 대상인 Object.values(providers)가 배열이 잘 나오는지 콘솔에 또 찍어봤습니다.

// src/app/components/SocialLoginBtn.tsx
'use client';

import { ClientSafeProvider, signIn } from 'next-auth/react';

type Props = {
  providers: Record<string, ClientSafeProvider>;
};

export default function SocialLoginBtn({ providers }: Props) {
  console.log(Object.values(providers));
}

배열도 잘 나오는 것을 확인했습니다. providersmap함수로 처리하는 과정에서 렌더링할 때 생기는 문제가 아니라는 것을 확인했습니다.


2. 두 번째 시도: 임의로 생긴 callbackUrl 파라미터때문에 생긴 문제인걸까?

앞서 문제 상황에서 설명했듯이 로그인은 잘 이루어지고 있었습니다.
(found: object with keys {redirect}) 오류 메시지에서 볼 수 있듯이
로그인이 성공한 후 페이지가 redirect 경로가 설정되어있지 않아서 생기는 문제가 아닐까 생각해보았습니다.



✅ 문제 해결


현재 page가 api/auth/signin경로에서 쿼리 스트링으로 callbackUrl 파라미터를 받고 있기 때문에 Next.js 공식문서에서 해당 쿼리 스트링의 값을 가져오는 방법을 찾았습니다.

useSearchParams은 React Hooks이기 때문에 클라이언트 컴포넌트에서만 현재 url의 쿼리스트링 값을 가져올 수 있습니다.

// src/app/components/SocialLoginBtn.tsx
'use client';

import { ClientSafeProvider, signIn } from 'next-auth/react';

type Props = {
  providers: Record<string, ClientSafeProvider>;
};

export default function SocialLoginBtn({ providers }: Props) {
    const searchParams = useSearchParams();
	const callbackUrl = searchParams.get('callbackUrl') as string;
  return (
    <div>
      {Object.values(providers).map((provider) => (
        <button
          key={provider.name}
          onClick={() => signIn(provider.id, 		
                 { callbackUrl } // 두 번째 인자로 전달 
          )}>
          {provider.name}로 로그인
        </button>
      ))}
    </div>
  );
}

callbackUrl의 값을 next-auth의 signIn 두 번째 인자로 optional하게 객체로 전달해주었습니다.

문제가 해결되었습니다!



💡 느낀점


Objects are not valid as a React child (found: object with keys {redirect}) 오류에 대한 글은 많았지만, next-auth 로그인 구현하다가 발생한 문제가 아니라서 대부분 객체를 불러오는 방법을 바꾸는 등으로 문제를 해결하는 것을 볼 수 있었습니다.

오류를 해결을 위해서는 오류 메시지 한 단어에 꽂히지 말고 다방면으로 시도하고, 그 과정에서 공식문서와 많이 친해져야겠다고 깨달았습니다.

profile
주니어 개발자 깡수 개발일지

0개의 댓글