참고 :
리액트 공식문서 고차 컴포넌트(higher-order-component)
책 : 실전 리액트 프로그래밍/이재승 저: 아래 작성된 예제 코드
with이름지정
규칙을 따름connect()
함수 / 라우터 - withRouter()
redux-connect()
사용 시 넘기지 않은 this.props.dispatch
를 사용할 수 있는 점redux-dispatch
를 사용, withMyHOC-dispatch
사용으로 충돌 => 마지막 값으로 덮어쓰기recompose/getDisplayName
패키지로 InputCompo의 displayName 불러와야함)hoist-non-react-statics
패키지 사용해야 함)아래의 HOC 사용 예제는 이재승 저, 실전 리액트 프로그래밍 책에 수록된 예제입니다. 자세한 설명과 함께 예제를 보기 원하시면 책을 보시길 추천!
with이름(InputCompo, 그밖에 인자들...)
작성 : 인자는 컴포넌트와, 추가로 필요한 인자들OuputCompo
를 반환하며, OuputCompo
의 반환값에는 inputCompo
를 지정// withMountEvent : 해당 HOC는 componentDidMount()될 때 이벤트가 발생!
function withMountEvent(InputCompo, compoName){ // 필요한 매개변수는 추가하기
return (
// 반환 컴포넌트 작성
class OutputComp extends React.Component {
// 마운트 라이프 사이클에서 이벤트 작성
componentDidMount() {
sendEvent(compoName);
}
render(){
return (
<InputCompo {...this.props} /> // InputCompo를 OuputCompo에서 반환
)
}
}
)
}
서버사이드렌더링(SSR)에서 화면 일부분이 클라이언트사이드렌더링(CSR)하기를 원할 경우 주로 사용하는 방식
// HOC 작성
function withHasMount(InputCompo){
return (
class OutputCompo extends React.Component {
state = {
hasMounted : false,
}
componentDidMount() {
this.setState({ hasMounted: true })
}
render(){
return (
<InputCompo {...this.props} hasMounted={this.state.hasMounted} />
// InputCompo에서 this.props.hasMounted 를 추가로 전달,
// hasMounted가 true일 경우 CSR!
)
}
}
)
}
// HOC 작성 : 함수형 작성
function withLogined(InputCompo){
return (
// props 분해
function({isLogin, ...props}){
return (
if(isLogin) return <InputCompo {...props} />;
if(!isLogin) return <p>권한이 없음니당~</p>;
)
}
)
}
props.isLogin
프로퍼티는 HOC를 벋어나면 불필요 함으로 제외하고 props를 넘김function withClassExtends (InputCompo) {
return (
class OutputCompo extends InputCompo {
// InputCompo의 인스턴스에 접근가능
}
)
}
InputCompo
의 인스턴스에 접근가능 : life-cycle, state, props, etc(methods, variable)// 디버깅 HOC
function withDebug (InputCompo) {
return (
class OutputCompo extends InputCompo {
render (){
return (
<>
// InputCompo의 props, state에 접근
<p>props: {JSON.stringify(this.props)}</p>
<p>state: {JSON.stringify(this.state)}</p>
{super.render()} // InputCompo의 render()호출
</>
)
}
}
)
}
InputCompo
의 props, state를 상속받아 화면에 출력super.render()
로 상속받은 render()
호출 function withWrappedDiv (InputCompo) {
return (
class OutputCompo extends InputCompo {
render (){
const inputRender = super.render();
return (
<>
{inputRender && inputRender.type === 'div'
? <InputCompo {...this.props} />
: <div><InputCompo {...this.props} /></div>
}
</>
)
}
}
)
}
InputCompo
를 상속받아 사용할 때 life-cycle 호출시 버그 발생 주의
약속된 위치에서 호출되는 life-cycle의 강제 호출은 버그 발생 야기한다.
div
태그로 감싸는 HOCsuper.render()
를 통해 render
의 요소가 div
인지 확인true
: <Inputcompo />
리턴false
div
요소로 감싼 <div><Inputcompo/></div>
or React.createElement('div', null, inputRender)
export default withOne(withTwo(withTree(InputCompo)))
디버깅 할때 편하게 하는 팁!
- displayName 값을 수정
// recompose/getDisplayName 패키지 사용
import getDisplayName from 'recompose/getDisplayName'
function withDisplayNameChange(InputCompo) {
class OutputCompo extends Component {
// ...
}
// getDisplayName을 통해 InputCompo의 displayName 값을 얻는다.
OutputCompo.displayName = `withDisplayNameChange(${getDisplayName(InputCompo)})`
return OutpoCompo
}
컴포넌트가 정적 메서드를 갖고 있을때, 정적메서드는 HOC에 전달되지 않음. hoist-non-react-statics
패키지를 통해 정적 메서드를 전달 받도록 한다.
import hoistNonReactStatic from 'hoist-non-react-statics'
function withStaticMethod (InputCompo){
class OutpuCompo extens React.Component {
// ...
}
// hoistNonReactStatic(정적 메서드 받을 컴포, 정적 메서드 보낼 컴포)
hoistNonReactStatic(OutputCompo, InputCompo)
return OuputCompo;
}
hoistNonReactStatic(정적 메서드 받을 컴포, 정적 메서드 보낼 컴포)
react-router
패키지의 withRouter
에서 위 방식 사용리액트 공식 문서 - Render Props 방식
랜더 속성 값(render-props) : 코드 재사용을 위한 함수타입의 속성값을 이용하는 패턴
CompoA
는 자주 사용할 컴포넌트CompoA
에서 render 될 때 내부 내용을 변경하고싶은데, 복붙-수정의 하드코딩으로 CompoB
를 만들어야해? N--Ooo! CompoA
에서 render-props방식을 사용해서 내부 내용을 전해줄 수 있음.props.children
으로 Layout
잡는 것과 비슷.
좋은글 감사합니다 ㅎㅎ