React 15 정착하면서 팀 룰로 정한 stateless functional component 패턴.
component 책임에 따라 두 종류로 나눔.
Stateless (Presentational) — props 받아서 JSX 내놓는 것만 하는 컴포넌트. 이벤트는 callback prop으로 위임. state 없음. 대부분은 이 형태로 충분.
const Badge = ({ text, onClick }) => (
<span className="badge" onClick={onClick}>{text}</span>
);
Badge.propTypes = {
text: PropTypes.string.isRequired,
onClick: PropTypes.func
};
Container (Class) — state 관리, lifecycle 필요한 경우. 데이터 fetch, Redux 연결 등.
class UserList extends React.Component {
state = { users: [], loading: true };
componentDidMount() {
fetch('/api/users')
.then(r => r.json())
.then(users => this.setState({ users, loading: false }));
}
render() {
if (this.state.loading) return <Spinner/>;
return (
<ul>{this.state.users.map(u => <Badge key={u.id} text={u.name}/>)}</ul>
);
}
}
효과:
- 컴포넌트 대부분이 stateless라 테스트가 엄청 쉬움. 그냥 props 넘기고 스냅샷 확인
- 재사용성 높아짐 — 로직 없이 표현만 담당하니까 다른 화면에도 붙일 수 있음
- 공식 문서에서도 "가능하면 functional로 써라" 라고 권장
주의: stateless component에는 아직 shouldComponentUpdate 같은 lifecycle 못 달아서 강제 memoize 필요하면 class로 돌아가야 함. React.PureComponent가 15부터 도입됐는데 이건 얕은 비교 기반이라 props에 객체가 깊게 있으면 안 먹음.
팀 컨벤션: 먼저 stateless로 작성 → 상태/사이드이펙트 필요해지면 class로 승격. 역방향 (class 먼저 작성 후 functional로 분해)은 하지 않도록. 이 습관이 리팩토링 시간 꽤 줄여줌.