기능 구현 - 특정 컴포넌트의 조건부 렌더링

이유승·2023년 12월 5일
0

기능 구현

목록 보기
21/21
post-custom-banner

웹 개발을 하다 보면, 모든 페이지에서 동일한 레이아웃을 사용하지 않는 경우가 종종 있다. 이럴 때 레이아웃 컴포넌트 자체를 여러 개 만들어서 상황에 따라 다른 레이아웃이 설정되도록 할 수 있지만, 단순히 특정 몇 개의 컴포넌트만이 렌더링 되지 않아야 된다고 한다면 굳이 레이아웃을 2개 이상 구성할 필요가 없다.



1. 레이아웃 구성과 조건부 렌더링

페이지 하단에 렌더링 되는 Footer 컴포넌트가 존재한다고 가정해보자. Footer는 어떤 페이지에서는 렌더링 되어야 하지만 어떤 페이지에서는 렌더링 되어서는 안된다. 이를 위해서는 어떤 방법을 사용해볼 수 있을까.

Context API 사용하기

Context API는 React의 전역 상태 관리 도구로, 여러 컴포넌트 간의 상태 공유에 유용하게 사용된다. 이 방법에서는 Layout 컴포넌트에서 Footer의 렌더링 여부를 결정하기 위해 전역 상태를 사용한다.

// LayoutContext.js
import React, { useState, createContext, useContext } from 'react';

const LayoutContext = createContext();

export const LayoutProvider = ({ children }) => {
  const [showFooter, setShowFooter] = useState(true);

  return (
    <LayoutContext.Provider value={{ showFooter, setShowFooter }}>
      {children}
    </LayoutContext.Provider>
  );
};

export const useLayout = () => useContext(LayoutContext);

Footer 컴포넌트를 렌더링 여부를 제어하는 useState를 포함하는 Context를 만들어 Provider로 적용한다. 그리고 아래와 같이 조건부 렌더링 방식을 통해 Footer 컴포넌트의 출력을 구성하면 된다.

// Layout 컴포넌트
import { useLayout } from './LayoutContext';

const Layout = ({ children }) => {
  const { showFooter } = useLayout();
  return (
    <div>
      {children}
      {showFooter && <Footer />}
    </div>
  );
};

페이지에서 직접 Layout 컴포넌트에 프롭스 전달하기

페이지 컴포넌트에서 Layout 컴포넌트로 프롭스를 전달하여 Footer의 렌더링을 제어하는 방법이다.

// Layout 컴포넌트
const Layout = ({ children, showFooter = true }) => (
  <div>
    {children}
    {showFooter && <Footer />}
  </div>
);

// 어떤 컴포넌트
const SomePage = () => (
  <Layout showFooter={false}>
    {/* 페이지 컨텐츠 */}
  </Layout>
);

Custom Hook 사용하기

Custom Hook을 만들어 현재 경로에 따라 Footer의 렌더링 여부를 결정할 수도 있다.

// useFooterVisibility.js
import { useLocation } from 'react-router-dom';

const useFooterVisibility = () => {
  const location = useLocation();
  const hideFooterOnPaths = ['/특정경로', '/또다른경로'];
  return !hideFooterOnPaths.includes(location.pathname);
};

// Layout 컴포넌트
const Layout = ({ children }) => {
  const showFooter = useFooterVisibility();
  return (
    <div>
      {children}
      {showFooter && <Footer />}
    </div>
  );
};



2. 각 방법의 장단점

Context API 사용하기

장점:

전체 프로젝트에 상태가 공유되어 언제 어디서든 간단하게 렌더링 여부를 제어할 수 있다.
기능의 변경이 필요할 때에 Context 파일 하나만 수정하면 된다.

단점:

작고 간단한 프로젝트에서는 Context API의 사용이 낭비일 수 있다.
상태가 바뀔때 마다 Context가 적용된 컴포넌트들이 모두 리렌더링되기 때문.

페이지에서 직접 Layout 컴포넌트에 프롭스 전달하기

장점:

간단하게 구현하고, 페이지 단위에서 직접 렌더링 여부를 제어할 수 있다.

단점:

컴포넌트마다 렌더링 로직을 구현해야해서 불필요한 코드 반복이 발생할 수 있다.

Custom Hook 사용하기

장점:

전체 프로젝트에 동일한 로직이 공유되어 언제 어디서든 간단하게 렌더링 여부를 제어할 수 있다.
기능의 변경이 필요할 때에 Custom Hook 파일 하나만 수정하면 된다.

단점:

작고 간단한 프로젝트에서는 Custom Hook을 따로 구현하는 것이 낭비가 될 수 있다.



3. 다른 방법들..

사실 특정 컴포넌트의 렌더링 여부를 제어하는 방법은 이외에도 존재한다.

고차함수 활용하기

  • 고차함수
    컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수
const withFooter = (Component) => (props) => (
  <div>
    <Component {...props} />
    <Footer />
  </div>
);

// 사용 예시
const PageWithFooter = withFooter(SomePage);

장점:

재사용성이 높고, 다양한 컴포넌트에 동일한 로직을 적용할 수 있다.
컴포넌트 구조를 변경하지 않고 추가적인 기능을 주입할 수 있다.

단점:

컴포넌트 계층이 복잡해질 수 있다.
React DevTools에서 컴포넌트가 HOC로 감싸진 것을 파악하기 어려울 수 있다.

Render Props 패턴 사용하기

const FooterControl = ({ children }) => {
  // Footer를 표시할지 말지 결정하는 로직
  const showFooter = determineFooterVisibility();
  return children(showFooter);
};

// 사용 예시
<FooterControl>
  {showFooter => (
    <div>
      <YourPage />
      {showFooter && <Footer />}
    </div>
  )}
</FooterControl>

장점:

컴포넌트 간의 상태 공유가 유연하며, 컴포넌트의 재사용성이 높아진다.
복잡한 로직을 캡슐화하고 컴포넌트 간에 공유할 수 있다.

단점:

JSX 코드가 복잡해질 수 있으며, 가독성이 떨어질 수 있다.

React Router의 Route Config 사용하기

<Route path="/page-with-footer" element={<PageWithFooter />} />
<Route path="/page-without-footer" element={<PageWithoutFooter />} />

장점:

URL 경로에 따라 컴포넌트를 직접적으로 제어할 수 있다.
라우팅 로직과 컴포넌트의 렌더링을 명확히 분리할 수 있다.

단점:

라우트 구성이 복잡해질 수 있다.
각 경로에 대해 별도의 컴포넌트를 정의해야 할 수도 있다.

profile
프론트엔드 개발자를 준비하고 있습니다.
post-custom-banner

0개의 댓글