HOC가 뭐야?
- 기능적인 필요성에 의해 반복되어 나타나는 코드들을 재사용할 수 있게 해준다.
- 반복되는 로직을 HOC에 넣어두고, 이를 통해 다른 컴포넌트를 Wrapping하는 방식으로 활용한다.
- 개인적인 해석으로 비유해보자면, 공통인수를 이용해서 인수분해를 하는 것과 의미적으로나 생김새적으로나 무척 비슷하다고 본다. (이런 느낌:
ax+ay = a(x+y)
)
HOC 사용법
- 리액트 컴포넌트를 인자로 받아서 새로운 리액트 컴포넌트를 리턴하게 한다.
- 주로 HOC 의 이름을 만들 땐 with___ 형식으로 지으며, 이 밑줄 부분에는 새로 주입될 prop명을 적어주면 나중에 prop의 출처를 명확히 파악하기에 좋다.(ex:
withNewPropName
)
HOC의 쓰임새
이 외에도 많은 쓰임새가 있겠으나, 유용할 만한 쓰임새를 나열했다.
- Container 컴포넌트와 Presentational 컴포넌트 분리 : Container 컴포넌트와 Presentational 컴포넌트를 분리하여 사용 할 때, 컨테이너 컴포넌트를 HOC를 만들어서 사용할 수 있다.
- 로딩 중 화면 표시 : 보통 SPA(Single Page App)에서 화면이 로딩 중일 때, Skeleton 화면을 보여주고, 로딩이 완료되면 데이터를 보여줄 때 사용 할 수 있다.
- 유저 인증 로직 처리: 컴포넌트 내에서 권한 체크나 로그인 상태를 체크하기 보다는 인증 로직을 HOC로 분리하면 컴포넌트 재사용성도 높일 수 있고, 컴포넌트에서 역할 분리도 쉽게 할 수 있다.
- 에러 메세지 표시: 컴포넌트 내에서 분기문(if/else 등)을 통해 처리 할 수도 있지만, 분기문을 HOC로 만들어 처리 하면 컴포넌트를 더욱 깔끔하게 사용 할 수 있다.
생김새
함수형 컴포넌트
const withHOC = WrappedComponent => {
const newProps = {
loading: false,
};
return props => {
return <WrappedComponent {...props} {...newProps} />
}
};
클래스형 컴포넌트
const withHOC = WrappedComponent => {
const newProps = {
loading: false,
};
return class extends React.Component {
render() {
return <WrappedComponent {...this.props} {...newProps} />
}
}
};
HOC로 wrapping하기
export default withHOC(AnyComponent);
예시 코드
아주 기본적인 예시
아래는 간단한 예제이다. 로딩여부에 따라 Loading
메시지를 보여줄 것인지, 컴포넌트를 보여줄 것인지 조건부 렌더링이 된다.
const withLoading = (WrappedComponent) => (props) => {
props.isLoading ? <div>Loading ...</div> : <WrappedComponent { ...props } />
}
위와 같이 정의한 HOC를 실제 사용할 때에는 이렇게 한다.
export default withLoading(TodoList);
좀더 발전된 상황의 예시
만일, 로딩 화면의 유형이 여러가지여서 유형에 따라 다른 컴포넌트를 보여주고 싶다면 이렇게 함수를 중첩하게끔 만들면 되겠다.
const withLoading = options => WrappedComponent => props => {
if (props.isLoading) {
if (options.type === 'circle') {
return <CircularLoading />
}
return <LinearLoading />
}
return <WrappedComponent {...props} />
};
{ type: 'circle'}
이 options라고 가정하면, 아래와 같이 활용하면 되겠다.
export default withLoading({ type: 'circle' })(TodoList);
[참고자료]
https://www.vobour.com/%EB%A6%AC%EC%95%A1%ED%8A%B8-react-%EC%9D%B4%ED%95%B4-4-higher-order-component
https://reactjs-kr.firebaseapp.com/docs/higher-order-components.html
https://velopert.com/3537