고차 컴포넌트
하나의 개발 패턴으로 컴포넌트를 인자로 받아서 새로운 컴포넌트로 변환해 반환하는 방식으로 인자로 넘긴 컴포넌트에게 추가되길 원하는 로직을 HOC에서 가지고 있다가 로직이 적용된 엘리멘트를 반환하게 된어 횡단 관심사 문제를 해결하는 역할을 한다.
횡단 관심사란?
대표적인 예시로 인증 & 인가 서비스, 로깅, 트랙젝션 처리, 에러처리 등등이 있으며 계층 분리를 통해서 기능을 분리한다고 하여도 중복된 코드가 생길 수 밖에 없는 경우가 있다 이러한 계층에 상관없이 공통적으로 필요한 관심사가 있는데 이것이 횡단 관심사이다.
즉 어플리케이션 전반에 공통적으로 필요한 문제를 횐단 관심사라고 부를 수 있다.
<App>
<Router>
<Container>
<Page>
// 이렇게 관심사 분리를 통해서 분리를 해도 공통적으로 필요한 로직이 있는 경우가 있다
언제 사용하는가?
횡단 관심사 문제를 해결하는데 사용되는데 쉽게 말하자면 동일한 작업을 여러번 반복하기 싫을 때 모듈화를 통해서 비슷한 유형을 다른 인자를 전달하므로 원하는 값을 출력할 수 있는데 HOC의 경우도 이러한 경우 사용된다.
데이터 패칭을 통해서 리스트를 보여주는 2개의 컴포넌트가 있다.
export default UserList(){
const [userList, setUserList] = useState([]);
useEffect(() => {
fetch('http://userList.plz.com/users')
.then(response => response.json())
.then(data => setUserList(data));
}, []);
return userList.length < 1 ? <Loading /> : (
<h2>UserList</h2>
{
userList.map(user => (
<div key={user.id}>
<p>name: {user.name}</p>
<p>email: {user.email}</p>
</div>
))
}
);
}
export default PostList(){
const [postList, setPostList] = useState([]);
useEffect(() => {
fetch('http://postList.plz.com/posts')
.then(response => response.json())
.then(data => setPostList(data));
}, []);
return postList.length < 1 ? <Loading /> : (
<h2>postList</h2>
{
postList.map(post => (
<div key={user.id}>
<p>{post.body}</p>
</div>
))
}
);
}
- 위 코드는 사실 불러온 데이터 값과 map()에 의해 돌아가는(표현되는) 아이템의 형태가 다를 뿐 나머지는 거의 동일한 형태의 컴포넌트이다.
- 이러한 경우 동일하게 수행되는 부분을 HOC를 통해서 표현하고 나머지 부분(표현되는 것)에 집중할 수 있다.
아래는 HOC를 통해서 새롭게 수정된 함수이다.
// withLoading.js
export default withLoading(WrappedComponent) {
return function({dataSource, ...otherProps}) {
const [data, setData] = useState([]);
useEffect(() => {
fetch(dataSource)
.then(response => response.json())
.then(data => setData(data));
}, []);
return data.length < 1 ? <Loading /> : <WrappedComponent data={data} {...otherProps} />
}
}
// UserList.jsx
const UserList = ({data}) => {
return data.length < 1 ? <Loading /> : (
<h2>UserList</h2>
{
data.map(user => (
<div key={user.id}>
<p>name: {user.name}</p>
<p>email: {user.email}</p>
</div>
))
}
);
}
export default withLoading(UserList);
이렇듯 우리는 HOC를 통해 동일 로직을 처리하며 간단하게 컴포넌트를 생성할 수 있다.
장 · 단점
장점
- 앞선 내용과 같이 한 곳에서 구현한 로직을 여러 컴포넌트에서 재사용할 수 있다.
- 동일 구현을 통해 버그 발생률을 줄일 수 있다.
- 관심사의 분리를 통해 가독성과 집중해서 구현할 수 있다.
단점
- props를 통해서 전달을 하게 되면서 중복되는 부분이 있고 이러한 부분에 대해서 props 병합을 통해서 결하게 될 시 코드에 대한 가독성이 나빠져 유지 보수 측면에서 방해가 된다.
function withStyles(Component) {
return props => {
const style = {
padding: '0.2rem',
margin: '1rem',
...props.style
}
return <Component style={style} {...props} />
}
}
const Button = () = <button style={{ color: 'red' }}>Click me!</button>
const StyledButton = withStyles(Button)
style에 대한 병합을 통해서 나타냄으로 파악하기 힘들어진 구조...
주의사항
- 항상 함수로 감싸줘야 한다.
- render 메소드 안에서 HOC를 사용하면 안된다.
- 정적 메소드는 따로 복사해야 한다.
- ref는 전달되지 않는다. (React.forwardRef API 사용)
참고자료
- https://jiyoon-park.tistory.com/entry/React-HOC%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90
- https://jiyoon-park.tistory.com/entry/React-HOC%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90
- https://velog.io/@hsk10271/HOC-feat.-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C (주의사항 설명용)
'CS > 프로그래밍' 카테고리의 다른 글
[CS Study] 디자인 패턴 (0) | 2024.02.04 |
---|---|
솔리드 원칙 (1) | 2024.01.20 |
CSS vs CSS-in-CSS vs CSS-in-JS (1) | 2024.01.13 |
CSS in JS (1) | 2024.01.13 |
화살표 함수와 일반 함수 (0) | 2024.01.08 |