React 컴포넌트 재사용을 위한 Higher-Order Component 패턴
문제 상황
어드민 대시보드를 만들면서 인증이 필요한 컴포넌트가 늘어났다. 각 컴포넌트마다 componentWillMount에서 로그인 체크를 하다 보니 동일한 코드가 반복됐다.
class Dashboard extends Component {
componentWillMount() {
if (!this.props.isAuthenticated) {
this.props.history.push('/login');
}
}
render() { /* ... */ }
}
HOC 패턴 적용
Higher-Order Component는 컴포넌트를 받아서 새로운 컴포넌트를 반환하는 함수다. 공통 로직을 HOC로 분리했다.
function withAuth(WrappedComponent) {
return class extends Component {
componentWillMount() {
if (!this.props.isAuthenticated) {
this.props.history.push('/login');
}
}
render() {
return this.props.isAuthenticated
? <WrappedComponent {...this.props} />
: null;
}
};
}
// 사용
const AuthenticatedDashboard = withAuth(Dashboard);
추가 개선
Redux의 connect처럼 여러 HOC를 조합할 수 있다. recompose 라이브러리도 검토 중이다.
const enhance = compose(
withAuth,
withLogging,
connect(mapStateToProps)
);
export default enhance(Dashboard);
주의사항
- HOC 내부에서 원본 컴포넌트를 수정하지 말 것
displayName을 설정해 디버깅을 쉽게 할 것- ref는 전달되지 않으므로 필요시 별도 처리
React 공식 문서에서도 권장하는 패턴이라 팀에 공유했다. Mixin보다 명확하고 조합하기 좋다.