프론트 개발자를 위한 여정

모든 영역을 안내하는 개발자

Frontend/React

[Container/Presentational 패턴] Container/Presentational 패턴이란?

ji-frontdev 2025. 4. 9. 10:00
728x90
반응형

프론트엔드 개발자로서 4~5년 전 React 프로젝트를 진행하면서 Container/Presentational 패턴을 사용했던 경험이 있다.
당시에는 패턴에 대해 깊이 이해한 상태는 아니었지만, 로직과 UI 코드가 얽혀 유지보수가 어려워지자 자연스럽게 관심사를 분리해야겠다는 필요를 느꼈고, 이 패턴을 도입했다.

돌아보면 그 선택은 꽤 합리적이었다. 그리고 최근 React의 패턴 흐름을 공부하면서,

과거의 구조와 현재의 방식이 어떻게 변화해왔는지를 다시 되짚어보게 되었다.


🧩 Container/Presentational 패턴이란?

1. 왜 나왔는가?

React가 등장한 초기에는 컴포넌트 안에서 로직, 상태, UI 모두를 처리하는 방식이 일반적이었다.
하지만 점점 규모가 커지고 협업이 늘어나면서, 다음과 같은 문제가 발생했다:

  • 하나의 컴포넌트에 너무 많은 책임이 모임
  • 테스트가 어려움
  • UI와 비즈니스 로직이 뒤섞여 가독성과 유지보수성이 저하됨

이러한 문제를 해결하기 위해 등장한 개념이 바로 Container/Presentational 패턴이다.
이는 2015년 Dan Abramov가 제안한 구조로, 관심사 분리를 명확히 하는 것이 목적이었다.

2. 어떻게 나누는가?

구성 요소 설명

  • Container Component
    • 상태와 로직 담당 (state, dispatch, API 호출 등)
    • 데이터를 가져오고, presentational 컴포넌트에 전달
  • Presentational Component
    • UI만 담당 (state 없음 또는 props만 사용)
    • CSS 스타일, HTML 구조, 사용자 입력 이벤트 처리 등
역할 구분 설명
Container Component 상태 관리, API 호출, 로직 처리 등을 담당
Presentational Component 데이터와 콜백을 props로 받아서 UI만 렌더링

예를 들어, 다음과 같은 구조다:

// Presentational
const TodoList = ({ todos }) => (
  <ul>
    {todos.map(todo => <li key={todo.id}>{todo.text}</li>)}
  </ul>
);

// Container
const TodoListContainer = () => {
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    fetch('/api/todos').then(res => res.json()).then(setTodos);
  }, []);

  return <TodoList todos={todos} />;
};
 

나도 이 패턴을 사용하면서, UI 컴포넌트를 순수하게 유지할 수 있었고, 로직 변경이 UI에 영향을 주지 않도록 관리할 수 있었다.

3. 강점

  • 관심사 분리로 인해 유지보수 쉬움
  • 재사용성 높은 컴포넌트 구조화 가능
  • 테스트 용이 (UI와 비즈니스 로직이 분리됨)

4. 단점과 현재 관점

  • 컴포넌트 수 증가 → 작은 프로젝트에선 과도할 수 있음
  • React의 Hooks 등장 이후 사용 빈도가 줄어듦
  • Custom Hook + Composition 패턴으로 대체되는 추세

🔄 현재는 왜 Custom Hook 패턴이 더 주목받는가?

React 16.8 이후, Hook의 등장은 React 개발 패러다임을 크게 바꾸었다.
이제는 Container 컴포넌트를 따로 만들지 않고도, 로직만을 Custom Hook으로 분리하는 것이 더 직관적이고 재사용성도 뛰어나다.

✅ Custom Hook 패턴이란?

// useTodos.ts
export const useTodos = () => {
  const [todos, setTodos] = useState([]);
  useEffect(() => { /* fetch logic */ }, []);
  return todos;
};

// TodoList.tsx
const TodoList = () => {
  const todos = useTodos();
  return <ul>{todos.map(...}</ul>;
};
 
 

📈 비교: Container/Presentational vs Custom Hook

 

항목 Container/Presentational Custom Hook
로직 재사용성 ❌ 컴포넌트 단위 ✅ 함수 단위
코드 중복 최소화 ✅ 높음
추상화 수준 높음 (명시적 구조) 더 유연함 (조합식 구조)
학습 난이도 쉬움 중간 (Hook 구조 이해 필요)
현재 추세 과거 주류 현재 표준적인 방식

🧠 나는 왜 그때 Container/Presentational을 선택했을까?

돌아보면, 당시 내가 Container/Presentational 구조를 택했던 이유는 단순했다.

  • 로직과 뷰가 섞이니 혼란스러웠고
  • 코드를 분리해서 더 명확하게 만들고 싶었으며
  • 유지보수 시, UI와 로직을 따로 다루는 것이 훨씬 효율적이라는 직관이 있었기 때문이다.

결국, 관심사 분리는 그 당시에도 필요했고 지금도 필요하다.
단지 그 방법이 Custom Hook이라는 도구로 더 유연하게 바뀌었을 뿐이다.


🔚 마무리하며 – 패턴은 목적이 아니다

Container/Presentational, Custom Hook, 혹은 하이브리드 패턴까지…
어떤 패턴이든 중요한 건 왜 이 구조를 택했는가?, 그리고 "이 구조가 팀과 프로젝트에 어떤 가치를 주는가?"이다.

지금은 Custom Hook 방식이 React의 표준적인 흐름으로 자리잡고 있지만,
과거의 Container/Presentational 방식 또한 당시의 문제를 해결한 좋은 구조였다.

나처럼 이전에 Container 패턴을 써본 사람이라면,
현재의 Custom Hook 구조도 충분히 자연스럽게 받아들일 수 있을 것이다.
그리고 그 흐름을 이해하는 것이, 더 좋은 구조를 선택하는 데 큰 힘이 된다.


2025.04.03 - [Frontend/React] - [Custom Hook 패턴] Custom Hook이란? 왜 필요한가? 언제 사용하면 좋은가?

 

[Custom Hook 패턴] Custom Hook이란? 왜 필요한가? 언제 사용하면 좋은가?

📌 Custom Hook 패턴 개요1️⃣ Custom Hook이란?Custom Hook은 React의 기존 Hooks(useState, useEffect, useContext 등) 을 조합하여반복되는 로직을 재사용 가능하도록 추출한 함수.컴포넌트 내부에서 자주 사용되

ji-frontdev.tistory.com

2025.04.03 - [Frontend/React] - [Custom Hook 패턴] Custom Hook 구조 및 작성 방법(MobX 클래스를 Custom Hook처럼 사용하면?)

 

[Custom Hook 패턴] Custom Hook 구조 및 작성 방법(MobX 클래스를 Custom Hook처럼 사용하면?)

1️⃣ Custom Hook 기본 구조Custom Hook은 기본적으로 함수형 컴포넌트 내부에서 재사용할 로직을 분리하는 패턴.📌 구성 요소반드시 use 접두사를 붙여야 함 → 예: useFetch, useAuth내부에서 React Hook(useS

ji-frontdev.tistory.com

 

728x90
반응형