디자인 패턴(Design Pattern)은 소프트웨어 설계에서 자주 발생하는 문제를 해결하기 위해 검증된 일반적인 해결책을 제공하는 템플릿이다. 이는 코드를 재사용 가능하고 유지보수가 쉬우며 확장 가능하게 설계하기 위해 사용된다. 디자인 패턴은 특정 언어나 프로젝트에 종속되지 않으며, 다양한 상황에 맞게 응용할 수 있다.
🕵️ 프레젠테이션-컨테이너 패턴에서는 UI와 비즈니스 로직을 명확히 분리하여 관리한다. UI는 프레젠테이션 컴포넌트로, 비즈니스 로직과 상태 관리는 컨테이너 컴포넌트로 분리된다.
src/
├── components/ # UI 컴포넌트 (프레젠테이션 컴포넌트)
│ └── UserList.jsx # 사용자 목록을 보여주는 UI 컴포넌트
├── containers/ # 비즈니스 로직을 담당하는 컴포넌트 (컨테이너 컴포넌트)
│ └── UserListContainer.jsx # 사용자 데이터를 처리하고 프레젠테이션 컴포넌트를 호출
└── App.jsx # 앱의 메인 컴포넌트
containers/UserListContainer.jsx
import { useState, useEffect } from "react";
import UserList from "../components/UserList";
const UserListContainer = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/users")
.then((res) => res.json())
.then((data) => {
setUsers(data);
setLoading(false);
});
}, []);
return <UserList users={users} loading={loading} />;
};
export default UserListContainer;
components/UserList.jsx
const UserList = ({ users, loading }) => {
if (loading) return <p>Loading...</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default UserList;
🕵️ 커스텀 훅 패턴에서는 비즈니스 로직을 훅으로 분리하고 UI는 그 훅을 활용하는 컴포넌트에서 처리한다. 따라서 폴더 구조는 훅을 중심으로 구성이 된다.
src/
├── components/ # UI 컴포넌트
│ └── UserList.jsx # 사용자 목록을 보여주는 UI 컴포넌트
├── hooks/ # 커스텀 훅
│ └── useUserData.js # 사용자 데이터를 처리하는 커스텀 훅
└── App.jsx # 앱의 메인 컴포넌트
components/
폴더는 UI 컴포넌트들을 보관한다. UI 컴포넌트는 로직을 알 필요 없이 커스텀 훅에서 제공하는 데이터를 props
로 받아 사용한다.hooks/
폴더는 커스텀 훅을 모아두는 폴더이다. 각 훅은 비즈니스 로직을 담당하며 재사용 가능하도록 만들어진다.hooks/useUserData.js
import { useState, useEffect } from "react";
const useUserData = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/users")
.then((res) => res.json())
.then((data) => {
setUsers(data);
setLoading(false);
});
}, []);
return { users, loading }; }; export default useUserData;
components/UserList.jsx
import useUserData from "../hooks/useUserData";
const UserList = () => {
const { users, loading } = useUserData();
if (loading) return <p>Loading...</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul> );
};
export default UserList;
프로젝트를 하면서 돌아보니 어느정도 획일화 된 패턴보다는 어느정도 장점을 모아서 구현해놓은거 같다.