[김민태의 데브캠프] React 디자인 패턴: 구현 패턴

vgotu99·2024년 12월 6일
post-thumbnail

JSX 내 조건부 렌더링을 위한 패턴

JSX에서 삼항 연산자를 사용한 조건부 렌더링은 간단한 경우 유용하지만, 복잡한 경우엔 가독성을 해치기 쉽다.

함수 추출

조건에 따라 렌더링할 UI를 함수로 분리한다.

const MyComponent = ({ isUserClick }) => {
  
  const renderButton = () => {
    return isUserClick ? (
      <button className="clicked">클릭됨</button>
    ) : (
      <button className="unclicked">클릭하기</button>
    );
  };

  return <div>{renderButton()}</div>;
}

언제 사용하나요?

  • 조건부 로직이 복잡해지고 JSX 코드가 길어질 때
  • UI를 분리하여 재사용 가능하게 하고 싶을 때

객체 매핑

조건별로 다른 UI를 객체로 관리한다.

const MyComponent = ({ isUserClick }) => {
  
  const buttonMap = {
    true: <button className="clicked">클릭됨</button>,
    false: <button className="unclicked">클릭하기</button>,
  };

  return <div>{buttonMap[isUserClick]}</div>;
}

언제 사용하나요?

  • 조건의 수가 많아지고, 로직이 단순 비교(값 매핑)일 때
  • 상태나 조건의 확장성이 필요할 때

Early Return

JSX 내에서 조건부 렌더링이 복잡할 경우, return을 빠르게 분기 처리한다.

const MyComponent = ({ isUserClick }) => {
  
  if (isUserClick) {
    return <button className="clicked">클릭됨</button>;
  }

  return <button className="unclicked">클릭하기</button>;
}

언제 사용하나요?

  • 각 조건에 대한 UI가 명확히 독립적일 때
  • 단순 조건 로직이 복잡한 JSX 안에서 산재되지 않도록 하고 싶을 때

배열 데이터를 JSX로 렌더링하기 위한 패턴

map을 사용하는 경우에는 반복되는 JSX 구조가 복잡해질 수 있으므로 다음과 같은 패턴을 사용할 수 있다.

컴포넌트 추출

배열의 각 항목을 렌더링하는 로직을 별도 컴포넌트로 분리한다.

const UserCard = ({ info }) => {
  
  return (
    <div className="user-card">
      <div>이름: {info.name}</div>
      <div>나이: {info.age}</div>
      <div>: {info.height}</div>
    </div>
  );
}

const UserList = ({ userInfo }) => {
  
  return (
    <div>
      {userInfo.map(info => (
        <UserCard key={info.id} info={info} />
      ))}
    </div>
  );
}

언제 사용하나요?

  • 렌더링 로직이 길거나 복잡할 때
  • 재사용 가능한 단위로 분리하고 싶을 때

분리된 로직 사용

map 함수 내의 복잡한 로직을 별도 함수로 추출한다.

const renderUserInfo = (info) => {
  
  return (
    <div className="user-card" key={info.id}>
      <div>이름: {info.name}</div>
      <div>나이: {info.age}</div>
      <div>: {info.height}</div>
    </div>
  );
}

const UserList = ({ userInfo }) => {
  
  return <div>{userInfo.map(renderUserInfo)}</div>;
}

언제 사용하나요?

  • 동일한 렌더링 로직을 여러 곳에서 재사용해야 할 때
  • 함수형 프로그래밍 스타일을 선호할 때

분리된 데이터 구조

데이터에 따라 그룹화하거나, 더 명확한 구조로 만들어 JSX에 전달한다.

const UserList = ({ userInfo }) => {
  const groupedUsers = userInfo.reduce((acc, user) => {
    const group = user.age > 30 ? 'adults' : 'youth';
    acc[group] = acc[group] || [];
    acc[group].push(user);
    
    return acc;
  }, {});

  return (
    <div>
      <h2>청소년</h2>
      {groupedUsers.youth?.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
      <h2>성인</h2>
      {groupedUsers.adults?.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
}

언제 사용하나요?

  • 데이터를 카테고리화하거나, 다양한 기준으로 나눌 필요가 있을 때
  • JSX 로직에서 데이터 정리를 미리 해두고 싶을 때

Return 내 JSX의 공통 패턴

역할별 섹션 구분

JSX를 역할별로 명확히 분리하여 가독성을 높인다.

const MyComponent = () => {
  const renderHeader = () => <header>헤더</header>;
  const renderContent = () => <main>메인 콘텐츠</main>;
  const renderFooter = () => <footer>푸터</footer>;

  return (
    <div>
      {renderHeader()}
      {renderContent()}
      {renderFooter()}
    </div>
  );
}

언제 사용하나요?

  • UI 구성 요소를 구조화하여 가독성을 높이고 싶을 때
  • 역할이 명확히 나뉘는 UI에서 섹션별로 분리하고 싶을 때

Higher-Order Component (HOC) 활용

공통된 패턴을 가진 JSX를 처리하는 고차 컴포넌트를 만든다.

const withCard = (WrappedComponent) => {
  const CardWrapper = (props) => {
    
    return (
      <div className="card">
        <WrappedComponent {...props} />
      </div>
    );
  };
  
  return CardWrapper;
};

const UserInfo = ({ name, age }) => {
  
  return (
    <div>
      <div>이름: {name}</div>
      <div>나이: {age}</div>
    </div>
  );
};

const UserInfoCard = withCard(UserInfo);

const App = () => {
  
  return <UserInfoCard name="홍길동" age={30} />;
};

export default App;

언제 사용하나요?

  • 공통된 레이아웃이나 스타일을 재사용해야 할 때.

0개의 댓글