고차함수 Higher-Order Components ( HOC )
- 고차 함수는 컴포넌트 로직을 재사용 하기 위한 기술이다.
- React API ( X )
- HOC의 이름은 with이름지정 규칙을 따른다.
- HOC는 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수
- 예) 리덕스 - connect() 함수 / 라우터 - withRouter()
재사용
// 답글 목록 컴포넌트
class CommentList extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
// "DataSource" is some global data source
comments: DataSource.getComments()
};
}
componentDidMount() {
// Subscribe to changes
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Clean up listener
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
// Update component state whenever the data source changes
this.setState({
comments: DataSource.getComments()
});
}
render() {
return (
<div>
{this.state.comments.map((comment) => (
<Comment comment={comment} key={comment.id} />))}
</div>);
}
}
// 블로그 포스트를 구독하는 컴포넌트
class BlogPost extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
blogPost: DataSource.getBlogPost(props.id)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
blogPost: DataSource.getBlogPost(this.props.id)
});
}
render() {
return <TextBlock text={this.state.blogPost} />;
}
}
위 두개의 코드는 답글 목록을 불러오는 컴포넌트와 블로그 포스트를 구독을 구현한 컴포넌트이다.
이 두개의 컴포넌트는 각자 다른 data 를 사용하고 렌더링의 결과는 다르지만 비슷한 점이 아래와 같다.
- 각자 mount 가 될 때 DataSource에 change listner 가 추가된다.
- listener 안에서는 setState를 통해 DataSource의 변화를 감지한다
- unmount 시 change listener 는 제거 된다.
이렇게 공통으로 사용하는 부분이 있기 때문에 하나의 로직으로 구성하고 이를 필요로 하는 컴포는트들이 공유를 하는 방식으로 만든다면 더욱 효율 적일 것이다. 이것을 해결하기 위해 고차 컴포넌트가 나왔다.
고차 컴포넌트로 해결
댓글목록이나 블로그포스트 같이 DataSource의 변화를 필요로 하는 컴포넌트를 만들기 위한 함수를 작석한다.
이 함수는 구독한 데이터를 prop으로 받는 자식 컴포넌트를 인자로 받아야 한다.
// withSubscription 이라는 함수를 만들었다
const CommentListWithSubscription = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
);
const BlogPostWithSubscription = withSubscription(
BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id)
);
withSubscription의 첫번째 인자로 component를 받고 있으며 두번째 인자로는 DataSource와 현재의 props를 회수하는 함수를 주었다.
이렇게 되면 CommentListWithSubscription and BlogPostWithSubscription이 렌더링 될때 답글목록과 블로그 포스트는 DataSource로 부터 회수한 가장 최신의 데이터를 prop 으로 넘기게 된다.
// 해당 함수는 컴포넌트를 받고
function withSubscription(WrappedComponent, selectData) {
// 또 다른 컴포넌트를 반환한다
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// WrappedComponent를 가장 최신의 데이터로 렌더링 한다.
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
로그인 체크 HOC 예제
// HOC 작성 : 함수형 작성
function withLogined(InputCompo){
return (
// props 분해
function({isLogin, ...props}){
return (
if(isLogin) return <InputCompo {...props} />;
if(!isLogin) return <p>권한이 없음니당~</p>;
)
}
)
}
- HOC 없이 구현하려면, 확인이 필요한 컴포넌트 마다 함수를 구현해야한다.
- props.isLogin 프로퍼티는 HOC를 벋어나면 불필요 함으로 제외하고 props를 넘김
HOC 사용 주의사항
- HOC를 렌더링 메소드 내부에서 사용하지 마라
- HOC 컴포넌트 내에서는 render 메소드를 사용할 수 없다.
- HOC는 모든 props를 넘길 수 있지만 ref에게는 똑같은 적용을 할 수 없다.
- HOC의 결과로 나오면 컴포넌트에 ref를 달기위해서는 React.forwardRef API를 사용해야 한다.
'Web > React.js' 카테고리의 다른 글
[STUDY] Hook 소개 (0) | 2021.03.18 |
---|---|
[STUDY] 성능 최적화 (0) | 2021.03.17 |
[STUDY] Ref 전달하기 (0) | 2021.03.15 |
[STUDY] 컨텍스트 (0) | 2021.03.13 |
[STUDY] 에러 경계 (0) | 2021.03.12 |
댓글