에러 발생
nextjs 에서 비동기 요청 과정 중 자연스러운 ui 흐름을 구성하기 위해 useSuspenseQuery + Suspense + react-error-boundary 를 활용하는 중 "Uncaught Error: Switched to client rendering because the server rendering errored" 에러 발생
"Uncaught Error: Switched to client rendering because the server rendering errored" 설명
이 에러는 Next.js에서 발생하며, 서버 사이드 렌더링(SSR) 중에 오류가 발생하여 **클라이언트 사이드 렌더링(CSR) 으로 자동 전환**되었음을 의미합니다.
- Next.js App Router 환경에서 서버 컴포넌트가 렌더링 도중 실패하면 발생합니다.
- 서버가 렌더링에 실패하더라도 페이지가 완전히 깨지는 걸 막기 위해, Next.js는 자동으로 CSR로 fallback합니다.
의문점
1. 클라이언트 컴포넌트에서 서버 랜더링?
useSuspenseQuery 를 사용하여 데이터를 fetch 하는 클라이언트 컴포넌트에서 발생한 오류라는 점
해결 : Suspense 사용은 nextjs 에서는 스트리밍을 구현하는 방법 중 하나, 즉 Suspense 로 감싸고 useSuspenseQuery 를 활용하는 과정에 서버에서 data 를 fetch 하게 됨
2. 401 Unauthorized 오류
첫 번째 fetch 과정(server)에서 401 Unauthorized 응답 즉 인증을 위한 쿠키를 전달 및 인증 과정에서 에러가 발생하고 이후 두 번째 fetch 과정(client)에서는 정상적인 응답 반환하는 점
해결 : 인증을 위해 쿠키를 사용하는데 서버에서는 쿠키에 접근 할 수 없어 인증정보 서버단계에서 전달하지 못하여 401 Unauthorized 응답하며 클라이언트에서는 정상 응답
해결 과정
1. 쿠키에 접근 할 수 없으니 다르 인증 방법 사용?
storage 나 메모리에 저장해서 쓰는 방법의 경우 각각 보안적인 측면 사용성의 측면에서
보안적인 측면에서 아쉬움이 있었고, CSR 이 사이트 성격에도 자연스러우므로 jwt 를 쿠키에 담아 사용하는 기존방식을 사용하는 방식이 조금 더 낫다고 판단
2. fetch 상태에 따른 ui 구성 방식 변경
기존 방식
useSuspenseQuery + Suspense + react-error-boundary 를 활용해 데이터를 불러오는 과정 중 loading 과정의 대체 ui 를 Suspense 의 fallback 으로 지정하고 error 가 발생 시 대체 ui 를 react-error-boundary 의 FallbackComponent 으로 지정
const Page = () => {
return (
<ErrorBoundary FallbackComponent={ <error fallback ui /> }>
<Suspense fallback={ <loading ui /> }>
<Content />
</Suspense>
</ErrorBoundary>
)
}
const Content = () => {
const { data } = useSuspenseQuery({
...
})
return (<div>{data}</div>)
}
개선 방식
useSuspenseQuery + Suspense 를 사용하지 않고 useQuery 를 통해 데이터를 불러오고 loading 과정에서 useQuery 의 isLoading, isSuccess 등의 상태에 맞게 data fetch 한 component 안에서 로딩 ui 를 직접 구현하도록 변경
const Page = () => {
return (
<ErrorBoundary FallbackComponent={ <error fallback ui /> }>
<Content />
</ErrorBoundary>
)
}
const Content = () => {
const { data, isSucess } = useQuery({
throwOnError: true, // 렌더링 단계에서 오류를 발생시키고 가장 가까운 오류 경계(error boundary) 로 전파
...
})
// isLoading 쓰지 않은 이유는 error, loading 일 때 data 타입이 undefined 일 수 있으므로 실제 error 발생시 error boundary 에서 처리하겠지만 type 이 특정되지 않으므로 !isSuccess 를 사용
if (!isSuccess) return <loading ui/>;
return (<div>{data}</div>)
}
참고
https://nextjs.org/docs/app/getting-started/fetching-data#with-suspense
https://tanstack.com/query/latest/docs/framework/react/examples/nextjs-suspense-streaming
'nextjs' 카테고리의 다른 글
[Nextjs 15] Route handler cors 설정 (0) | 2025.02.07 |
---|---|
Next.js 환경에서 express, MSW 를 활용한 mock 서버 (1) | 2025.01.05 |
nextjs middleware.js | ts (0) | 2024.11.26 |
[error] next/image Un-configured Host (0) | 2023.07.10 |
비동기 데이터로 jsx 구성 시 최적화 및 예외 처리 (0) | 2023.06.23 |