[React] HOC(High Order Component)란?

seohyun Kang·2022년 8월 3일
0

React

목록 보기
2/9

Introduction

고차 컴포넌트 (HOC : High Order Component)는 "컴포넌트 로직을 재사용하기 위한 React의 고급 기술"이라고 React 공식 문서에 작성되어 있습니다.

고차 컴포넌트는 컴포넌트를 인자로 받아 새로운 컴포넌트를 리턴하는 함수입니다.

const EnhancedComponent = higherOrderComponent(WrappedComponent);

이러한 방식으로 고차 컴포넌트에 인자로 전달되는 모든 컴포넌트는 고차 컴포넌트에 정의된 함수를 사용할 수 있는 새 컴포넌트로 변화하여 재사용성을 높일 수 있습니다.

이러한 고차 컴포넌트(HOC)는 Redux의 connect와 Relay의 createFragmentContainer와 같은 서드 파티 React 라이브러리에서 흔하게 볼 수 있습니다.

Usage

고차 컴포넌트는 어떻게 사용할 수 있을까? 이해를 돕기 위해 React 예제를 사용하겠습니다.

아래는 외부로부터 데이터를 구독하여 댓글 목록을 렌더링하는 CommentList 컴포넌트입니다.

class CommentList extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {
      // "DataSource" 는 글로벌 데이터 소스입니다.
      comments: DataSource.getComments()
    };
  }

  componentDidMount() {
    // 변화감지를 위해 리스너를 추가합니다.
    DataSource.addChangeListener(this.handleChange);
  }

  componentWillUnmount() {
    // 리스너를 제거합니다.
    DataSource.removeChangeListener(this.handleChange);
  }

  handleChange() {
    // 데이터 소스가 변경될때 마다 comments를 업데이트합니다.
    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} />;
  }
}

두 컴포넌트를 확인해보면 상당한 유사성을 확인할 수 있습니다. handleChange, state, listener를 공통적으로 가지고 있습니다.

우리는 공통되는 부분 확인하고 해당 부분을 재사용하면 좋겠다라는 생각이 들게 될 것 입니다.

그렇다면 아래와 같이 수정해 보겠습니다.

// 이 함수는 컴포넌트를 매개변수로 받고..
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() {
      // ... 래핑된 컴포넌트를 새로운 데이터로 랜더링 합니다!
      // 컴포넌트에 추가로 props를 내려주는 것에 주목하세요.
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

이와 같은 과정을 통해 우리는 코드의 재사용성을 높일 수 있게 되었습니다.


Reference : React Docs - High Order Component

0개의 댓글