(React) Presentational & Container 디자인 패턴

Dragon·2024년 2월 25일

위클리 페이퍼

목록 보기
16/18
post-thumbnail

Presentational & Container 디자인 패턴

리액트 애플리케이션에서 컴포넌트를 구성하고 관리하는 방식을 설명하는 용어로, 컴포넌트의 역할과 책임을 분리하여 코드를 보다 모듈화하고 유지보수하기 쉽도록 설계하는 데 도움을 준다.

이 패턴을 사용하면 애플리케이션 로직에서 뷰를 분리하는게 가능하다.

컨테이너(Container) 컴포넌트

위 예시에서 DogImagesContainer 컴포넌트로, 데이터와 상태를 관리하고 프레젠테이션 컴포넌트를 제어한다.
비즈니스 로직이나 상태 관리를 담당하며, 주로 fetch 와 같은 API 호출이나 상태 업데이트 등의 작업을 처리한다.
프레젠테이션 컴포넌트들을 조합하여 하나의 기능을 구현하고 관리하게 된다.

코드 예시

// DogImagesContainer.jsx

import React, { useState, useEffect } from 'react';
import DogImages from './DogImages';

const DogImagesContainer = () => {
  // 개의 이미지들을 저장할 상태와 로딩 상태를 관리.
  const [dogImages, setDogImages] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // 컴포넌트가 마운트된 후에 개의 이미지들을 가져오는 비동기 함수를 호출.
    fetchDogs();
  }, []);

  const fetchDogs = async () => {
    try {
      // API를 통해 개의 이미지들을 가져오기.
      const response = await fetch('https://dog.ceo/api/breeds/image/random/5');
      const data = await response.json();
      // 가져온 이미지들을 상태에 업데이트하고 로딩 상태를 false로 변경.
      setDogImages(data.message);
      setIsLoading(false);
    } catch (error) {
      console.error('Error fetching dog images:', error);
      setIsLoading(false);
    }
  };

  return (
    <div>
      {/* 로딩 중일 때는 'Loading...'을, 로딩이 완료된 후에는 DogImages 컴포넌트를 렌더링. */}
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <DogImages images={dogImages} />
      )}
    </div>
  );
};

export default DogImagesContainer;

프레젠테이션(Presentational) 컴포넌트

위 예시에서 DogImages 컴포넌트로, UI를 표시하는 뷰 역할을 하고 사용자 인터랙션을 다루지 않는 순수한 컴포넌트이다.
재사용 가능한 UI 컴포넌트를 작성하는 데 사용되며, 주로 props를 통해 데이터를 전달받아 해당 데이터를 UI로 렌더링한다.

코드 예시

// DogImages.jsx

import React from 'react';

const DogImages = ({ images }) => (
  <div>
    <h2>Dog Images</h2>
    <div>
      {/* 이미지 배열을 매핑하여 각 이미지를 화면에 출력. */}
      {images.map((image, index) => (
        <img key={index} src={image} alt={`Dog ${index}`} style={{ width: '200px', margin: '5px' }} />
      ))}
    </div>
  </div>
);

export default DogImages;

장단점

장점

  1. 모듈화와 재사용성: 프레젠테이션 컴포넌트는 UI만 다루므로 재사용성이 높고 독립적으로 유지될 수 있어, 이는 코드의 모듈화와 유지보수를 용이하게 만든다.

  2. 테스트 용이성: 프레젠테이션 컴포넌트와 컨테이너 컴포넌트의 분리로 테스트가 간소화된다. UI 컴포넌트를 테스트할 때는 props만 주입하여 테스트할 수 있으며, 비즈니스 로직을 다루는 컨테이너 컴포넌트를 별도로 테스트할 수 있다.

  3. 유연성: 컨테이너 컴포넌트와 프레젠테이션 컴포넌트를 분리함으로써, 레이아웃 변경이나 비즈니스 로직 변경에 따른 영향을 최소화할 수 있다.

단점

  1. 추가적인 추상화: 두 가지 컴포넌트 유형을 구현하기 위해 추가적인 추상화가 필요할 수 있어, 이로 인해 초기 설정이 복잡해질 수 있다.

  2. 명확한 경계 설정 필요: 프레젠테이션 컴포넌트와 컨테이너 컴포넌트 간의 명확한 경계를 설정해야 하므로, 이를 위해 일관된 네이밍 규칙과 코드 스타일을 정의하는 것이 중요하다.


참고 페이지
https://www.patterns.dev/react/presentational-container-pattern

profile
2024년부터 시작하는 프론트엔드 개발 공부

0개의 댓글