개발자

Next.js SSR + react-query 조합에서의 serializing 에러

2023년 02월 14일조회 2,467

안녕하세요! Next.js SSR + react-query 조합을 사용하려고 하는데요, page 컴포넌트 내 getServerSideProps 함수에서 prefetching을 받아온 후에 serializing 에러가 발생합니다. (Next.js는 13버젼입니다.) 에러 내용은 다음과 같습니다. Error: Error serializing `.dehydratedState.queries[0].state.data.headers` returned from `getServerSideProps` in "/top". Reason: `object` ("[object AxiosHeaders]") cannot be serialized as JSON. Please only return JSON serializable data types. 해당 에러 내용으로 구글링을 해보니, 대부분 getServerSideProps 함수 반환 코드에서 return { props: { dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), }, }; 와 같이 dehydrate(queryClient)값을 JSON화 -> Object화를 하라고 하는데요, 이와 같이 사용해도 또 다시 아래와 같은 에러가 납니다. TypeError: Converting circular structure to JSON --> starting at object with constructor 'ClientRequest' | property 'socket' -> object with constructor 'Socket' --- property '_httpMessage' closes the circle Backend API는 Express.js를 사용하고 있으며, res.status(200).json({ data: ~ })와 같은 방식으로 응답을 주고 있습니다. 어떻게 해결할 수 있을까요? 코드 첨부가 안되네요, 아래는 page 컴포넌트가 위치한 파일의 전체 코드입니다. import type { ReactElement } from 'react'; import { dehydrate, QueryClient, useQuery } from '@tanstack/react-query'; import { format } from 'date-fns'; import TopMusicContainer from '~containers/TopMusicContainer'; import Layout from '~layouts/Layout'; import type { NextPageWithLayout } from '~pages/_app'; import TopMusicService from '~services/topMusicService'; import * as MusicType from '~types/musicType'; export async function getServerSideProps() { const queryClient = new QueryClient(); await queryClient.prefetchQuery(['fetchTopMusic'], () => { const params: MusicType.ListRequestType = { filter: 'title', keyword: '', page: 1, limit: 25, time: format(new Date(), 'yyyyMMddHH'), }; return TopMusicService.list(params); }); return { props: { dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), }, }; } const Top: NextPageWithLayout = (): JSX.Element => { const { data, isLoading } = useQuery({ queryKey: ['fetchTopMusic'], queryFn: () => { const params: MusicType.ListRequestType = { filter: 'title', keyword: '', page: 1, limit: 25, time: format(new Date(), 'yyyyMMddHH'), }; return TopMusicService.list(params); }, }); return ( <section> <TopMusicContainer /> </section> ); }; Top.getLayout = function getLayout(page: ReactElement) { return <Layout>{page}</Layout>; }; export default Top;

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 2

손정현님의 프로필 사진

안녕하세요. Axios response를 그대로 사용하시면 함수 등 JSON으로 변환이 불가능한 것들이 포함되어 있어서 axios response에서 data만 추출해야 하는 것으로 알고 있는데요. 혹시 TopMusicService.list(params); 의 리턴 타입이 어떻게 되나요? 참고한 SO 포스트: - https://stackoverflow.com/questions/67204170/getserversideprops-functions-response-cannot-be-serialized-as-json-in-next-js

profile picture

익명

작성자

2023년 02월 14일

안녕하세요! TopMusicService.list(params)의 타입은 AxiosResponse<any, any>입니다.

손정현님의 프로필 사진

손정현

coya2023년 02월 14일

앗 그렇다면 useQuery의 queryFunc에서 해당 값에서 data만 추출하시면 어떻게 되나요? ex) const result = await TopMusicService.list(params) const data = result.data return data

profile picture

익명

작성자

2023년 02월 15일

어라 말씀하신대로 data만 빼서 리턴하니까 정상적으로 동작합니다!! 감사합니다🙇🏻‍♂️

커리어리 AI 봇님의 프로필 사진

안녕하세요! 에러 메시지를 보면 dehydratedState의 queries 배열 안에 있는 첫 번째 쿼리의 state.data.headers를 JSON으로 직렬화 할 수 없다는 것 같습니다. 이는 headers가 AxiosHeaders 객체로서 직렬화 할 수 없는 객체라서 발생한 문제입니다. 이 문제를 해결하기 위해서는 dehydrate 함수를 사용할 때 serialize 함수를 직접 구현해서 headers 객체를 직렬화하도록 해야 합니다. 아래와 같이 코드를 수정해보세요. serialize 함수는 JSON.stringify를 사용하되, 값이 Headers 객체일 경우 serializeHeaders 함수를 사용하여 객체를 직렬화 합니다. serializeHeaders 함수에서는 Headers 객체를 Record<string, string> 타입으로 변환하도록 구현했습니다. 위와 같이 수정하면 직렬화 에러를 해결할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
export async function getServerSideProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery(['fetchTopMusic'], () => {
    const params: MusicType.ListRequestType = {
      filter: 'title',
      keyword: '',
      page: 1,
      limit: 25,
      time: format(new Date(), 'yyyyMMddHH'),
    };
    return TopMusicService.list(params);
  });

  return {
    props: {
      dehydratedState: serialize(dehydrate(queryClient)),
    },
  };
}

function serialize(obj: any) {
  const str = JSON.stringify(obj, (_, value) =>
    value instanceof Headers ? serializeHeaders(value) : value
  );
  return JSON.parse(str);
}

function serializeHeaders(headers: Headers) {
  const obj: Record<string, string> = {};
  headers.forEach((value, key) => {
    obj[key] = value;
  });
  return obj;
}

커리어리 AI 봇의 답변을 평가해 주세요!

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!