Skip to content

react hooks가 특정 조건에서 실행되면 안되는 이유 & useQuery에 query function 매개변수가 undefined일 수도 있을 때 어떻게 해결할까 ‐ 2024.11.18

Dongwoo Ko edited this page Nov 20, 2024 · 1 revision

문제 상황

import { useQuery } from '@tanstack/react-query';
import Chart from 'components/StocksDetail/Chart';
import Header from 'components/StocksDetail/Header';
import PriceSection from 'components/StocksDetail/PriceSection';
import TradeSection from 'components/StocksDetail/TradeSection';
import { useParams } from 'react-router-dom';
import { getStocksByCode } from 'service/stocks';

export default function StocksDetail() {
  const params = useParams();
  const { id } = params;

  if (!id) return;

  const { data, isLoading } = useQuery(['stocks', id], () =>
    getStocksByCode(id),
  );

  if (isLoading) return;
  if (!data) return;

  return (
    <div className='flex flex-col'>
      <Header code={id} />
      <div className='flex h-[500px]'>
        <div className='flex min-w-[850px] flex-col'>
          <Chart code={id} />
          <PriceSection />
        </div>
        <TradeSection />
      </div>
    </div>
  );
}

React Hook "useQuery" is called conditionally. React Hooks must be called in the exact same order in every component render. 에러 발생!!

리액트 훅 ‘useQuery’가 특정 조건에서만 실행되어서 생긴 에러다.

useQuery는 id가 undefined일 경우에는 실행되지 않기 때문이다.

왜 특정조건에 실행되면 안될까?

React는 Hook 호출의 순서를 보장해야 하므로 모든 렌더링에서 같은 순서로 호출되어야 한다!

예를 들어 useState, useEffect hooks 간에도 정해진 호출 순서가 있기 때문이다.

→ 즉, 결론은 이러한 문제 때문에 리액트 훅은 조건문들을 거치지 않게 가장 최상위에 선언해주어야 한다!

https://velog.io/@jazzyfact95/TIL-React-React-Hook-is-called-conditionally.-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0

오케이 useQuery가 조건에 걸리지 않도록 위에 선언해보자

import { useQuery } from '@tanstack/react-query';
import Chart from 'components/StocksDetail/Chart';
import Header from 'components/StocksDetail/Header';
import PriceSection from 'components/StocksDetail/PriceSection';
import TradeSection from 'components/StocksDetail/TradeSection';
import { useParams } from 'react-router-dom';
import { getStocksByCode } from 'service/stocks';

export default function StocksDetail() {
  const params = useParams();
  const { id } = params;

  const { data, isLoading } = useQuery(['stocks', id], () =>
    getStocksByCode(id),
  );

  if (!id) return;

  if (isLoading) return;
  if (!data) return;

  return (
    <div className='flex flex-col'>
      <Header code={id} />
      <div className='flex h-[500px]'>
        <div className='flex min-w-[850px] flex-col'>
          <Chart code={id} />
          <PriceSection />
        </div>
        <TradeSection />
      </div>
    </div>
  );
}

Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'. 에러 발생

useQuery에서 실행하는 getStocksByCode 함수가 매개변수로 id를 받고 있고 id에 타입은 undefined일수도 있기 때문에 생긴 오류이다. 이걸 어떻게 해결할 수 있을까?

문제 해결

import { useQuery } from '@tanstack/react-query';
import Chart from 'components/StocksDetail/Chart';
import Header from 'components/StocksDetail/Header';
import PriceSection from 'components/StocksDetail/PriceSection';
import TradeSection from 'components/StocksDetail/TradeSection';
import { useParams } from 'react-router-dom';
import { getStocksByCode } from 'service/stocks';

export default function StocksDetail() {
  const params = useParams();
  const { id } = params;

  const { data, isLoading } = useQuery(
    ['stocks', id],
    () => getStocksByCode(id!),
    { enabled: !!id },
  );

  if (!id) {
    return;
  }

  if (isLoading) return;
  if (!data) return;

  return (
    <div className='flex flex-col'>
      <Header code={id} />
      <div className='flex h-[500px]'>
        <div className='flex min-w-[850px] flex-col'>
          <Chart code={id} />
          <PriceSection />
        </div>
        <TradeSection />
      </div>
    </div>
  );
}

리액트 쿼리 enabled 옵션을 활용해서 해결할 수 있다.

enabled 옵션은 무엇일까?

React Query의 enabled 옵션은 특정 조건이 충족될 때만 쿼리를 실행하도록 제어하는 데 사용된다.

enabledboolean 값을 받으며, 쿼리가 실행 가능한지를 결정한다.

  • enabled: true (기본값): 쿼리 즉시 실행.
  • enabled: false: 쿼리가 실행되지 않고, useQuery는 초기 상태(isLoading: false, data: undefined, 등)를 유지

→ 즉 enabled !!id로 id가 undefined일 경우 false로 변환해 값을 넣어주면서 쿼리를 실행하지 않도록 할 수 있다.

쿼리가 실행되었다는 것은 id가 무조건 존재함을 보장할 수 있기에getStocksByCode(id!) 처럼 **Non-Null Assertion Operator(!)**으로 id가 undefined가 아니라고 단언해도 괜찮다고 생각한다.

📜 개발 일지

⚠️ 트러블 슈팅

❗ 규칙

🗒️ 기록

기획
회의록
데일리스크럼
그룹 멘토링
그룹 회고

😲 개별 멘토링

고동우
김진
서산
이시은
박진명
Clone this wiki locally