🧱 컴포넌트 재사용성과 UX 확장성을 고려한 구조 설계
지금 만드는 컴포넌트, 6개월 뒤에도 재활용할 수 있을까?
🎯 왜 재사용성과 확장성이 중요한가?
React는 “컴포넌트 기반” UI 라이브러리입니다.
즉, 하나의 기능 단위를 컴포넌트로 쪼개서 관리하고, 필요한 곳에 불러와 재사용하는 것이 기본 철학이죠.
하지만 기능은 잘 돌아가지만 재사용할 수 없는 컴포넌트,
또는 한 번 만들어놓고 다른 페이지에 쓸 수 없는 UI 구조를 보면
장기적인 유지보수와 확장에 큰 문제가 생깁니다.
💡 좋은 컴포넌트란?
반복 가능한 기능을 담고 있고, 다양한 상황에서 유연하게 쓸 수 있는 구성입니다.
✅ 재사용성과 확장성을 고려할 때의 기준
항목 | 고려할 점 |
---|---|
Props 구조 | 유연하고 예측 가능한가? 필수 vs 선택 구분 |
내부 상태 관리 | 외부 제어가 가능한가? (Controlled 방식) |
스타일링 | 상속/오버라이드 가능한 구조인가? |
역할 분리 | UI + 로직이 잘 분리되어 있는가? |
UX 이벤트 | 인터랙션(hover, 클릭 등)을 외부에서 제어 가능하게 했는가? |
에러 처리 | 예외 상황에도 유연한가? |
1. UI 컴포넌트와 로직 컴포넌트는 분리하자
가장 많이 실수하는 부분 중 하나는 UI와 로직을 하나의 컴포넌트에 모두 넣는 것입니다.
❌ 예: 너무 많은 걸 혼자 다 하는 버튼
function SubmitButton() {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
await submitForm();
setLoading(false);
};
return <button onClick={handleClick}>{loading ? '저장 중...' : '저장'}</button>;
}
✅ 개선: UI 컴포넌트와 로직 분리
function LoadingButton({ onClick, loading, children }) {
return <button onClick={onClick} disabled={loading}>
{loading ? '처리 중...' : children}
</button>;
}
function SubmitSection() {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
await submitForm();
setLoading(false);
};
return <LoadingButton onClick={handleClick} loading={loading}>저장</LoadingButton>;
}
👉 컴포넌트 하나가 너무 많은 책임을 지면 재사용이 어려워집니다.
→ 역할 분리 원칙(Single Responsibility Principle) 을 따르자.
2. Props는 유연하지만 명확하게
너무 많은 props, 또는 애매한 props는 해독을 어렵게 만듭니다.
- 필수 props는
isRequired
또는 TypeScript 명시 - 불리언보다 명확한 문자열/enum 사용
variant
,size
,type
등은 공통 패턴
예시: 토스트 컴포넌트
<Toast message="성공!" variant="success" duration={3000} />
<Toast message="에러 발생!" variant="error" />
📌 variant
값은 'success' | 'error' | 'info' | 'warning' 등으로 명확하게 정의
3. Controlled vs Uncontrolled: 외부 제어 가능하게
Controlled 컴포넌트란 외부에서 상태를 제어할 수 있는 구조입니다.
예시: Modal 컴포넌트
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal">
<div className="content">{children}</div>
<button onClick={onClose}>닫기</button>
</div>
);
}
const [open, setOpen] = useState(false);
return (
<>
<button onClick={() => setOpen(true)}>열기</button>
<Modal isOpen={open} onClose={() => setOpen(false)} />
</>
);
✅ 내부 상태보다 외부 제어가 더 유연하고 테스트하기 쉽습니다.
4. Custom Hook으로 로직 분리하기
로직은 Hook으로, UI는 View로 나누면 재사용성과 테스트성이 높아집니다.
function useToast() {
const [toasts, setToasts] = useState([]);
const addToast = (msg) => {
const id = Date.now();
setToasts((prev) => [...prev, { id, msg }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 3000);
};
return { toasts, addToast };
}
사용 예:
const { toasts, addToast } = useToast();
addToast("저장되었습니다!");
5. Context를 Provider 단위로 구성하기
예시: ToastProvider
const ToastContext = createContext();
export function ToastProvider({ children }) {
const toastApi = useToast();
return (
<ToastContext.Provider value={toastApi}>
{children}
<ToastContainer toasts={toastApi.toasts} />
</ToastContext.Provider>
);
}
export function useToastContext() {
return useContext(ToastContext);
}
📌 Provider는 UI 렌더링과 로직 제공을 함께 할 수 있어 유지보수성이 높습니다.
6. 스타일 확장 가능한 방식으로 구성하기
className
병합 처리- styled-components, Tailwind 등 확장 가능한 도구 사용
variant
props로 스타일 분기 처리
function Button({ children, className, ...rest }) {
return <button className={`base-button ${className}`} {...rest}>{children}</button>;
}
✔ 유연한 스타일 구조는 디자인 시스템 구성에도 유리합니다.
✨ 마무리 요약
React에서 재사용성과 확장성은 코드 유지보수성과 UX 일관성에 매우 중요한 요소입니다.
UI와 로직을 적절히 분리하고, 유연한 props 구조와 외부 제어 가능한 구조를 설계하면
단순한 컴포넌트도 멀티 환경, 다양한 UX에서 쉽게 재사용할 수 있습니다.
🔑 핵심 요약 체크리스트
- ✅ UI와 로직은 분리 (Custom Hook, 역할 분리)
- ✅ props는 명확하고 유연하게
- ✅ 외부 제어(Controlled) 방식 우선
- ✅ 상태 로직은 Hook화해서 재사용
- ✅ Context로 UI 기능 Provider 설계
- ✅ 스타일은 className 병합 or styled 방식으로 확장성 확보
“잘 만든 컴포넌트 하나, 열 기능 안 부럽다.”
나중에 또 써도 불편함 없는 구조, 그게 진짜 실력입니다 😎
'일상이 개발' 카테고리의 다른 글
React 폴더 구조 완전 가이드: 유지보수성과 확장성을 높이는 설계 전략 (0) | 2025.04.08 |
---|---|
React 상태 관리 완전 정복: Context, Zustand, Redux 비교와 선택 가이드 (0) | 2025.04.07 |
React에서 상태가 바뀌었음을 '느끼게' 만드는 실전 인터랙션 패턴 모음 (0) | 2025.04.07 |
React 오류 처리 UX 완전 정복: 실패 상황에서도 친절한 앱 만들기 (0) | 2025.04.07 |
React 토스트/스낵바 UX 가이드: 실시간 피드백 제대로 설계하는 방법 (0) | 2025.04.06 |