Container/Presentational Parttern
2024.06.07
React 컴포넌트를 만들때 다음과 같은 상황이 있을 수 있습니다.
-
복잡도의 증가 하나의 UI 컴포넌트안에 넘겨받은 데이터를 처리하는 로직이 너무 길어서 가독성과 유지 보수성을 높일 필요성 증가
-
재사용 가능한 컴포넌트의 필요성 UI는 같지만 도메인 별로 비즈니스 로직이 다른 경우, 컴포넌트를 재사용하기 위해 분리의 필요성 증가
React 컴포넌트를 작성할때 재사용성과 유지 보수를 생각할때 가장 처음으로 적용할 만한 패턴으로 Container/Presentational Parttern
이 있습니다.
1. Container/Presentational Pattern 이란?
화면과 비즈니스 로직을 분리하는 패턴으로 컴포넌트를 두가지로 나눕니다.
- Presentational Components
- UI를 담당
- 상태를 갖지 않고, 전달받은 props를 화면에 렌더링
- 스타일링 및 레이아웃 중심으로 작성되며, DOM 이벤트를 처리하는 정도의 단순한 역할
- 재사용성을 염두에 두고 설계
- Container Components
- 비즈니스 로직을 처리
- 데이터를 API에서 가져오고, 상태(state)를 관리
- 자식으로 Presentational Component를 렌더링하며, 데이터를 속성(props)으로 전달
- UI와의 의존성이 적으며, 로직 중심
2. 예시
- Presentational Components
/presentational.tsx
const TodoList = ({ todos, onAddTodo, onToggleTodo }) => {
const handleAddClick = () => {
onAddTodo(input);
};
return (
<div>
<h1>Todo List</h1>
<ul>
{todos.map((todo, index) => (
<li
key={index}
style={{
textDecoration: todo.completed ? "line-through" : "none",
cursor: "pointer",
}}
onClick={() => onToggleTodo(index)}
>
{todo.text}
</li>
))}
</ul>
</div>
);
};
export default TodoList;
- Container Components
/Container.tsx
const TodoContainer = () => {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
setTodos([...todos, { text, completed: false }]);
};
const toggleTodo = (index) => {
setTodos(
todos.map((todo, i) =>
i === index ? { ...todo, completed: !todo.completed } : todo
)
);
};
return <TodoList todos={todos} onAddTodo={addTodo} onToggleTodo={toggleTodo} />;
};
3. 결론
처음에 이 패턴을 접하고 꽤 유용하다고 생각했습니다. 하지만 컴포넌트 하나의 복잡도가 높지 않을때에는 유용했으나, Container Component에서 데이터를 가져오고, 상태를 관리하며, 이벤트 핸들링까지 모두 처리하게 되면, 복잡도가 너무 증가하게 되고 계속해서 컴포넌트를 작은 단위로 분리해주는 작업이 필요했습니다.
또한 Presentational Components도 재사용성을 염두해 만들다보면 Props가 과도하게 많아지게 되는 경우가 생기기도 합니다.
<Comp opt1={...} opt2={...} opt3={...} opt4={...} opt5={...} opt6={...} opt7={...} opt8={...} ... />
그리고 도메인 단위로 작은 컴포넌트를 관리할때에는 이러한 분리는 오히려 여러 파일들의 깊이가 늘어 유지보수에 불편함을 가져오게 됩니다. 그래서 상황에 따라서 조금더 유연한 컴포넌트 설계를 위해 Compound, Hooks 패턴등을 적용하여 설계를 했습니다.