Query data cannot be undefined | React-Query

Bori·2023년 7월 17일
2

어쨌든 공부

목록 보기
24/41

React-Query를 이용한 SSR

React Query는 prefetch를 지원합니다.
Next.js의 경우 다음과 같은 방식으로 SSR을 수행할 수 있습니다.

// pages/posts.jsx
import { dehydrate, QueryClient, useQuery } from '@tanstack/react-query'
import type { GetServerSideProps, NextPage } from 'next';

const Posts: NextPage = () => {
  const { data } = useQuery(['posts'], getPosts)

  // ...
}

export const getServerSideProps: GetServerSideProps = () => {
  const queryClient = new QueryClient()

  await queryClient.prefetchQuery(['posts'], getPosts)

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

export default Posts;

Query data cannot be undefined 에러

SSR을 적용하기 위해 다음과 같이 코드를 작성했습니다.

export const getServerSideProps: GetServerSideProps = async () => {
  // ...
  
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery([queryKeys.users, username], async () => {
    await api.getProfileByUsername({ username });
  });

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

그리고 다음과 같은 에러가 발생했습니다.

해당 에러에 대해 구글링 했을 때 useQuery 사용시 등록한 함수가 Promise 를 반환하지 않는 경우 이와 같은 에러가 발생할 수 있다는 내용을 찾았습니다.

하지만 저의 경우 prefetchQuery 에서 발생한 에러였고, prefetchQuery 에 등록한 함수가 Promise를 반환하고 있었습니다.
또한 모든 SSR에서 발생한 에러가 아니었기에 코드를 다른 SSR 코드와 비교하면서 천천히 확인해보았습니다.
그리고 정말 작은 차이점을 발견했습니다!

원인

다음은 정상적으로 동작하는 코드입니다.

export const getServerSideProps: GetServerSideProps = async () => {
  // ...
  
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery(
    [queryKeys.users, username],
    async () => await api.getProfileByUsername({ username }),

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

혹시 이 전의 문제가 있었던 코드와의 차이점을 찾으셨나요?

에러의 원인은 중괄호였습니다(또는 누락된 return 키워드).
에러가 발생했던 코드는 prefetchQuery 에 등록한 함수에 return 키워드 없이 중괄호가 사용되었습니다.

화살표 함수 사용 방법

화살표 함수는 본문이 한 줄인 함수의 결과를 반환할 때 다음과 같이 작성할 수 있습니다.

const func = (...arge) => expression;
const func = (...arge) => {
  return expression;
}

결과적으로 에러 발생의 원인은 화살표 함수를 잘못 사용하여 정상적으로 Promise 를 반환하지 못했기 때문이었습니다.

해결 방법

그래서 prefetchQuery 에 등록할 함수를 다음과 같이 작성하면 정상적으로 동작합니다.

// Error
async () => {
  await api.getProfileByUsername({ username });
}

// OK
async () => await api.getProfileByUsername({ username })
// OK
async () => {
    return await api.getProfileByUsername({ username });
}

마무리

  • 기존의 코드를 그대로 복붙해서 사용하는 api만 변경했는데, 그 과정에서 ESLint가 중괄호를 삽입하면서 발생한 에러였습니다.
  • 얼핏 보기에 큰 차이점을 찾지 못해 당황스러웠는데 해결하고 보니 약간은 허무하기도..
  • ESLint가 자동으로 변환한 코드의 경우 한번 더 확인의 필요성을 단단히 느낀 경험이었습니다.

참고

2개의 댓글

comment-user-thumbnail
2023년 7월 18일

정말 좋은 글 감사합니다!

1개의 답글