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

위 예시에서 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;
위 예시에서 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;
모듈화와 재사용성: 프레젠테이션 컴포넌트는 UI만 다루므로 재사용성이 높고 독립적으로 유지될 수 있어, 이는 코드의 모듈화와 유지보수를 용이하게 만든다.
테스트 용이성: 프레젠테이션 컴포넌트와 컨테이너 컴포넌트의 분리로 테스트가 간소화된다. UI 컴포넌트를 테스트할 때는 props만 주입하여 테스트할 수 있으며, 비즈니스 로직을 다루는 컨테이너 컴포넌트를 별도로 테스트할 수 있다.
유연성: 컨테이너 컴포넌트와 프레젠테이션 컴포넌트를 분리함으로써, 레이아웃 변경이나 비즈니스 로직 변경에 따른 영향을 최소화할 수 있다.
추가적인 추상화: 두 가지 컴포넌트 유형을 구현하기 위해 추가적인 추상화가 필요할 수 있어, 이로 인해 초기 설정이 복잡해질 수 있다.
명확한 경계 설정 필요: 프레젠테이션 컴포넌트와 컨테이너 컴포넌트 간의 명확한 경계를 설정해야 하므로, 이를 위해 일관된 네이밍 규칙과 코드 스타일을 정의하는 것이 중요하다.
참고 페이지
https://www.patterns.dev/react/presentational-container-pattern