HOC란?
컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수, HOC function
컴포넌트 로직을 재사용하기 위한 react의 고급 기술 → 로직을 한 곳에서 정의하고 많은 컴포넌트에서 로직을 공유할 수 있게 하는 추상화를 가능하게 한다.
인자로 받은 컴포넌트에 특정 기능을 부여한다.
- 고차 컴포넌트는 사이드 이펙트가 전혀 없는 순수 함수
- 코드의 반복을 줄일 수 있다.
- 비지니스 로직, 뷰를 분리하기 위한 목적으로도 쓰인다.
- 원본 컴포넌트를 변경하지 않고 조합할 수 있다.
컴포넌트 로직을 재사용할 수 있다/
ex1) 로그인 상태에 따른 토글 로직을 HOC를 사용하여 토글 기능에 따라 보여줄 컴포넌트를 인자로 전달 → withToggle HOC를 가지고 여러 곳에서 토글 기능 사용 가능!
ex2) 모든 포스트를 나열하는 컴포넌트, 모든 댓글을 나열하는 컴포넌트 → 로직이 동일: http get 요청을 통해 데이터를 받아온 후 state에 저장, 데이터를 렌더링 → 포스트를 보여주는 컴포넌트, 댓글을 보여주는 컴포넌트를 withRequest HOC에 각각 인자로 넘겨주어 만들어진 컴포넌트 사용 → 로직을 공유!
ex3) withRouter HOC: 라우트 컴포넌트가 아닌 곳에서 match/location/history를 사용해야 할 때 사용된다. react-router-dom 라이브러리로부터 가져와서 쓸 수 있다.
- HOC함수의 네이밍은 주로 with로 시작
HOC 구조
const WrappedComponent = () => { return ... }
// 모듈을 export할 때 단순히 WrappedComponent가 아닌,
// withHOC 함수에서 리턴된 enhanced WrappedComponent를 리턴하는 것.
export default withHOC(WrappedComponent);
예시
예시 1) withToggle HOC
// refactoring 생략
const WrappedComponent1 = () => { return ... };
const WrappedComponent2 = () => { return ... };
const withToogle = (WrappedComponent) => {
return (props) => {
return props.show ? <WrappedComponent {...props} /> : false;
};
}
export withToggle(WrappedComponent1);
export withToggle(WrappedComponent2);
예시 2) withRequest HOC
const WrappedComponent1 = () => { return ... }; // Post component
const WrappedComponent2 = () => { return ... }; // Comment component
const withRequest = (url) => (WrappedComponent) => {
return (props) => {
const [data, setData] = useState(null);
useEffect(()=> {
try {
const response = await axios.get(url);
setData(response.data);
} catch (e) {
console.log(e);
}
}, []);
return (
<WrappedComponent {...props} data={data}/>
);
};
};
export withRequest(/* url for posts */)(WrappedComponent1);
export withRequest/* url for comments */)(WrappedComponent2);
예시 3) withRouter
import { withRouter } from 'react-router-dom';
const WithRouterSample = ({ location, match, history }) => {
return (
<div>
<button onClick={() => history.goBack()}>뒤로가기</button>
<button onClick={() => history.push('/')}>홈으로</button>
</div>
);
};
export default withRouter(WithRouterSample);
import WithRouterSample from 'hoc/WithRouterSample';
const UseWithRouterSample = () => {
// ...
return <WithRouterSample />;
};
React에서 제공하는 useParams, useHistory, useRouteMatch, useLocation 라우터 훅을 사용해서도 라우트 컴포넌트가 아닌 곳에서 match/location/history를 사용할 수 있다.