[React 디자인 패턴] Layout Components

지은·2023년 6월 13일
3

⚛️ React

목록 보기
20/23
post-custom-banner

디자인 패턴

: 애플리케이션 개발 과정에서 공통적으로 발생하는 문제들에 대한 효과적이고 표준적인 솔루션

React 애플리케이션을 개발할 때 많이 마주치는 문제들로 다음과 같은 문제들이 있다.

  1. 재사용 가능한 레이아웃 만들기
    e.g. split screen, list, modal 등
  2. 여러 개의 컴포넌트에서 복잡한 로직 재사용하기
    e.g. 서버로부터 데이터를 가져오는 로직
  3. 폼(form) 사용하기
  4. 함수형으로 프로그래밍하기

이를 해결하기 위한 디자인 패턴들을 알아보자.

출처 : Layout Components | React Design Pattern -2


레이아웃 컴포넌트

레이아웃 컴포넌트는 페이지의 전체 구조와 배치를 정의하는 역할을 하며, 안에 다른 컴포넌트들을 배치할 수 있다.

레이아웃 컴포넌트의 주요 개념

레이아웃 컴포넌트를 사용하는 이유는 페이지에 사용되는 컴포넌트들이 자신이 페이지에 어디에 위치하는지 알거나 신경쓰지 않게 하기 위해서다.

  • 이를 통해 개발자는 컴포넌트를 개별적으로 관리하고 구성할 수 있으며,컴포넌트들은 자신의 로직과 상태에 집중하여 독립적으로 작동하여 재사용성과 유지보수성이 향상된다.
  • 또한 페이지의 레이아웃과 구조에 집중할 수 있어, 페이지 구조를 일관성 있게 유지하고 디자인 시스템을 관리하기 쉬워진다.

➡️ 개별 컴포넌트를 더 쉽게 구성하고 관리 & 페이지 구조에 집중하여 더 효율적인 개발이 가능하게 한다.


예제

분할 화면 (Split Screens)

App.js

const LeftHandComponent = ({ name }) => {
  return (
    <Container>
      <h1>{name}</h1>
    </Container>
  );
};

const RightHandComponent = ({ message }) => {
  return (
    <Container>
      <p>{message}</p>
    </Container>
  );
};

function App() {
  return (
    <SplitScreen leftWeight={1} rightWeight={3}>
      <LeftHandComponent name="Title" />               // children으로 내려준다.
      <RightHandComponent message="this is message" />
    </SplitScreen>
  );
}

SplitScreen.js

const Container = styled.div`
  display: flex;
`;

const Box = styled.div`
  flex: ${(props) => props.weight}; // props로 받은 가중치(weight) 사용
`;

const SplitScreen = ({ children, leftWeight = 1, rightWeight = 1 }) => {
  const [left, right] = children; 
  // children으로 LeftHandComponent와 RightHandComponent 엘리먼트를 받는다.
  
  return (
    <Container>
      <Box weight={leftWeight}>{left}</Box>   // 변수에 할당해 사용
      <Box weight={rightWeight}>{right}</Box>
    </Container>
  );
};

리스트 (List)

App.js

function App() {
  return (
    <>
      <RegularLlist
        items={products}
        resourceName="product"
        itemComponent={SmallProductListItem}
      />
      <RegularLlist
        items={products}
        resourceName="product"
        itemComponent={LargeProductListItem}
      />

      <NumberedList
        items={products}
        resourceName="product"
        itemComponent={SmallProductListItem}
      />

      <NumberedList
        items={products}
        resourceName="product"
        itemComponent={LargeProductListItem}
      />
    </>
  );
}

RegularList.js

const RegularLlist = ({
  items,
  resourceName,
  itemComponent: ItemComponent
}) => {
  return (
    <>
      {items.map((item, i) => (
        <ItemComponent key={i} {...{ [resourceName]: item }} /> // resourceName={item} 으로 전달됨
      ))}
    </>
  );
};

NumberedList.js

const NumberedList = ({
  items,
  resourceName,
  itemComponent: ItemComponent
}) => {
  return (
    <>
      {items.map((item, i) => (
        <>
          <h3>{i + 1}</h3>
          <ItemComponent key={i} {...{ [resourceName]: item }} />
        </>
      ))}
    </>
  );
};

SmallProductListItem.js

const SmallProductListItem = ({ product }) => {
  const { name, price } = product;

  return (
    <p>
      {name} - {price}
    </p>
  );
};

LargeProductListItem.js

const LargeProductListItem = ({ product }) => {
  const { name, price, description, rating } = product;

  return (
    <>
      <h3>{name}</h3>
      <p>{price}</p>
      <p>Description: {description}</p>
      <p>Average Rating: {rating}</p>
    </>
  );
};

모달 (Modal)

App.js

App() {
  return (
    <Modal>
      <LargeProductListItem product={products[0]} />
    </Modal>
  );
}

Modal.js

const Modal = ({ children }) => {
  const [shouldShow, setShouldShow] = useState(false);

  return (
    <>
      <button onClick={() => setShouldShow(true)}>Show Modal</button>
      {shouldShow && (
        <ModalBackground onClick={() => setShouldShow(false)}>
          <ModalBody onClick={(e) => e.stopPropagation()}> // 이벤트 버블링 방지
            <button onClick={() => setShouldShow(false)}>X</button>
            {children}
          </ModalBody>
        </ModalBackground>
      )}
    </>
  );
};
profile
블로그 이전 -> https://janechun.tistory.com
post-custom-banner

4개의 댓글

comment-user-thumbnail
2023년 6월 16일

고생하셨습니다ㅎㅎ

답글 달기
comment-user-thumbnail
2023년 6월 18일

한 번 정리하고 가면 좋다 생각한 내용이네요 ! 감사합니당

답글 달기
comment-user-thumbnail
2023년 6월 18일

코드 예제가 있으니까 더 보기 좋네욤 ㅎㅎ

답글 달기
comment-user-thumbnail
2023년 6월 18일

실행 코드가 있어서 더 이해가 잘 되었던 것 같아요! 고생하셨습니다 ㅎㅎ

답글 달기