[ React ] 디버깅을 방해하는 Early Return, 이렇게 잡는다

0_jin·2025년 3월 31일
1

React에서 JSX는 함수 실행 결과로 렌더링되기 때문에, 종종 예상치 못한 동작이 발생할 수 있습니다.
특히 컴포넌트 내부에 early return이 존재할 경우, JSX 상에는 존재하는 컴포넌트가 실제 화면에서는 렌더링되지 않는 상황이 발생합니다.

🧩 문제 상황

다음과 같은 코드가 있다고 가정합니다.

<Flex direction='col' gap='gap-y-[20px]'>
  <CreatorBrowse />
  <GameCommunityBrowse />
  <CreatorsCampaign />
  <CampaignBrowse />
  <RankingBrowse />
  <BottomBanner />
</Flex>

해당 코드로 렌더링 된 페이지는 다음과 같습니다.

해당 코드는 페이지를 블럭 단위로 구성한 간단한 예제입니다.

코드와 렌더링된 페이지를 유추해보면, <CampaignBrowse /> 는 분명 JSX로 렌더링이 명시되어 있지만, 실제 페이지에는 렌더링되지 않습니다.

이는 해당 컴포넌트 내부에서 조건에 따라 null을 반환하는 early return 로직 때문입니다.

위 예제 코드는 블럭 단위로 페이지를 쌓았기에 비교적 파악이 쉽지만, 조금 더 복잡한 코드에서는 파악이 더욱 어려워집니다.

🔍 원인 분석

CampaignBrowse 컴포넌트의 내부는 다음과 같습니다.

const CampaignBrowse = () => {
  const data = use데이터핸들링hook();
  const a = use또다른hook1();
  const b = use또다른hook2();

  if (data.length === 0) return null;

  return <div>...</div>;
};

이 코드는 다음과 같은 문제를 일으킵니다.

  • 컴포넌트가 렌더링되지 않는 이유를 외부에서 직관적으로 파악하기 어렵다.
  • 디버깅 시 JSX와 실제 DOM 간 불일치로 혼란을 유발한다.
  • 조건을 만족하지 않아도 불필요한 훅이 실행되어 리소스 낭비가 발생할 수 있다.
  • 컴포넌트 본연의 역할이 아닌, 렌더링 조건까지 책임지고 있어 응집도가 떨어진다.

🛠️ 첫 번째 개선 시도: 조건을 외부로 분리

렌더링 조건을 Page 컴포넌트에서 관리하도록 개선할 수 있습니다.

const Page = () => {
  const data = use데이터핸들링hook();
  const isCampaignBrowseRender = data.length !== 0;

  return (
    <Flex direction='col' gap='gap-y-[20px]'>
      <CreatorBrowse />
      <GameCommunityBrowse />
      <CreatorsCampaign />
      {isCampaignBrowseRender && <CampaignBrowse />}
      <RankingBrowse />
      <BottomBanner />
    </Flex>
  );
};

const CampaignBrowse = () => {
  const data = use데이터핸들링hook();
  const a = use또다른hook1();
  const b = use또다른hook2();
  return <div>...</div>;
};

이렇게 하면 CampaignBrowse가 렌더링될지 여부를 외부에서 명확하게 판단할 수 있습니다.

그러나 이 방식은

  • Page 컴포넌트가 지나치게 많은 렌더링 조건과 상태를 갖게 되어 가독성이 떨어질 수 있다.
  • 로직이 복잡해질 경우 상태 관리와 데이터 흐름 파악이 어려워진다.

라는 한계를 가집니다.

💡 궁극적인 해결 방안: Function as Child Component

렌더링 여부에 필요한 로직을 별도의 컴포넌트로 분리하고, Function as Child 패턴을 활용합니다.

const Page = () => {
  return (
    <Flex direction='col' gap='gap-y-[20px]'>
      <CreatorBrowse />
      <GameCommunityBrowse />
      <CreatorsCampaign />
      <CampaignBrowseRenderProvider>
        {({ isRender }) => isRender && <CampaignBrowse />}
      </CampaignBrowseRenderProvider>
      <RankingBrowse />
      <BottomBanner />
    </Flex>
  );
};

const CampaignBrowseRenderProvider = ({
  children,
}: {
  children: ({ isRender }: { isRender: boolean }) => React.ReactNode;
}) => {
  const data = use데이터핸들링hook();
  const isRender = data.length !== 0;
  return children({ isRender });
};

✅ 이 방식의 장점

  • CampaignBrowse는 렌더링 조건을 신경 쓰지 않고 자신의 역할에 집중한다.
  • Page 컴포넌트는 필요한 영역에만 로직을 캡슐화하여 전체 가독성을 유지한다.
  • 조건 분기 로직이 분리되고 재사용성 또한 확보할 수 있다.
  • 리소스 낭비 없이 불필요한 hook 호출도 방지한다.

🧵 마치며

컴포넌트 단위의 책임을 분리하고 렌더링 조건을 명확하게 관리하는 방식은 규모가 커질수록 더욱 빛을 발한다고 생각합니다.
단순한 개선처럼 보일 수 있지만, 이러한 패턴은 실제 개발 생산성과 유지보수성에 큰 영향을 미칩니다.


다른 의견이나 더 좋은 방안이 있다면 댓글 작성해주시면 감사드리겠습니다.

profile
가독성 좋은 코드, 성능 개선, 좋은 dx 경험, 자동화 를 생각합니다.

0개의 댓글

관련 채용 정보