이 글은 주로 React 고차 컴포넌트에 대한 심층적인 이해를 제공합니다. React 고차 컴포넌트에 대해 좀 더 명확하게 이해하시기 바랍니다.
1. React에서 HOC(고차 컴포넌트)는 컴포넌트 로직을 재사용하기 위한 고급 기술입니다. HOC는 React API의 일부가 아닙니다. HOC는 구성 요소를 가져와서 새 구성 요소를 반환하는 함수입니다. React에서 컴포넌트는 코드 재사용의 기본 단위입니다.
2. HOC를 설명하려면 다음 두 가지 예를 들어보세요.
CommentList 구성 요소는 주석 목록을 렌더링하고 목록의 데이터는 외부 소스에서 가져옵니다.
class CommentList extends React.Component { constructor() { super(); 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 ( <p> {this.state.comments.map((comment) => ( <Comment comment={comment} key={comment.id} /> ))} </p> ); } }
다음은 블로그 정보를 표시하는 데 사용되는 BlogPost 컴포넌트입니다.
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} />; } }
두 컴포넌트는 서로 다르며 DataSource의 다른 메소드를 호출하고 출력도 다르지만 그 중 대부분의 구현은 동일합니다. :
1. 로딩이 완료된 후 DataSource에 변경 리스너를 추가합니다
2. 데이터 소스가 변경되면 리스너 내부에서 setState를 호출합니다. 3. 제거 후 변경 리스너를 제거합니다
const CommentListWithSubscription = withSubscription( CommentList, (DataSource) => DataSource.getComments() ); const BlogPostWithSubscription = withSubscription( BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id) );withSubscription 호출 시 전달되는 첫 번째 매개변수는 래핑된 컴포넌트이고, 두 번째 매개변수는 데이터를 검색하는 데 사용되는 함수입니다.
// This function takes a component... function withSubscription(WrappedComponent, selectData) { // ...and returns another component... return class extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { data: selectData(DataSource, props) }; } componentDidMount() { // ... that takes care of the subscription... DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { DataSource.removeChangeListener(this.handleChange); } handleChange() { this.setState({ data: selectData(DataSource, this.props) }); } render() { // ... and renders the wrapped component with the fresh data! // Notice that we pass through any additional props return <WrappedComponent data={this.state.data} {...this.props} />; } }; }HOC는 입력 구성 요소를 수정하지 않으며 상속을 사용하여 동작을 재사용하지도 않습니다. HOC는 단지 함수일 뿐입니다. 래핑된 구성 요소는 컨테이너의 모든 prop을 허용하고 래핑된 구성 요소의 출력을 렌더링하는 데 사용되는 새 prop(데이터)도 허용합니다. HOC는 데이터가 어떻게 사용되는지, 왜 데이터가 사용되는지 신경 쓰지 않으며 래핑된 구성 요소는 데이터를 어디서 가져오는지 신경 쓰지 않습니다.
function logProps(InputComponent) { InputComponent.prototype.componentWillReceiveProps = function(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); }; // The fact that we're returning the original input is a hint that it has // been mutated. return InputComponent; } // EnhancedComponent will log whenever props are received const EnhancedComponent = logProps(InputComponent);여기에는 몇 가지 문제가 있습니다. 1. 가져온 컴포넌트는 향상된 컴포넌트와 별도로 재사용할 수 없습니다. 2. EnhancedComponent에 다른 HOC를 적용하면 componentWillReceiveProps도 변경됩니다.
function logProps(WrappedComponent) { return class extends React.Component { componentWillReceiveProps(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); } render() { // Wraps the input component in a container, without mutating it. Good! return <WrappedComponent {...this.props} />; } } }이 새로운 logProps는 이전 logProps와 동일한 기능을 가지고 있지만 새로운 logProps는 잠재적인 충돌을 방지합니다. 클래스 유형 구성 요소와 함수 유형 구성 요소에도 동일하게 적용됩니다. 2. 렌더링 메서드에 HOC를 사용하지 마세요React의 diff 알고리즘은 구성 요소의 ID를 사용하여 기존 하위 트리를 업데이트할지 아니면 이전 하위 트리를 해체하고 렌더링에서 반환된 경우 새 하위 트리를 로드할지 결정합니다. 메소드 구성 요소가 이전에 렌더링된 구성 요소와 동일(===)하면 React는 diff 알고리즘을 통해 이전에 렌더링된 구성 요소를 업데이트합니다. 그렇지 않으면 이전에 렌더링된 하위 트리가 완전히 언로드됩니다.
render() { // A new version of EnhancedComponent is created on every render // EnhancedComponent1 !== EnhancedComponent2 const EnhancedComponent = enhance(MyComponent); // That causes the entire subtree to unmount/remount each time! return <EnhancedComponent />; }결과 구성 요소가 한 번만 생성되도록 구성 요소 정의 외부에서 HOC를 사용하세요. 몇몇 경우에는 HOC를 동적으로 적용해야 하며, 라이프 사이클 함수나 생성자에서 이를 수행해야 합니다. 3. 정적 메서드는 수동으로 복사해야 합니다. 때때로 React 구성 요소에 정적 메서드를 정의하는 것이 매우 유용합니다. 컴포넌트에 HOC를 적용하면 원래 컴포넌트가 컨테이너 컴포넌트에 래핑되더라도 반환된 새 컴포넌트에는 원래 컴포넌트의 정적 메서드가 없습니다.
// Define a static method WrappedComponent.staticMethod = function() {/*...*/} // Now apply an HOC const EnhancedComponent = enhance(WrappedComponent); // The enhanced component has no static method typeof EnhancedComponent.staticMethod === 'undefined' // true반환된 구성 요소가 원본 구성 요소의 정적 메서드를 가지려면 함수 내부에서 원본 구성 요소의 정적 메서드를 새 구성 요소에 복사해야 합니다.
function enhance(WrappedComponent) { class Enhance extends React.Component {/*...*/} // Must know exactly which method(s) to copy :( // 你也能够借助第三方工具 Enhance.staticMethod = WrappedComponent.staticMethod; return Enhance; }4. 컨테이너 컴포넌트의 참조는 래핑된 컴포넌트로 전달되지 않습니다.컨테이너 컴포넌트의 props는 래핑된 컴포넌트로 쉽게 전달될 수 있지만 컨테이너 컴포넌트의 참조는 전달되지 않습니다. 래핑된 구성 요소에. HOC를 통해 반환된 구성 요소에 대한 참조를 설정하면 이 참조는 래핑된 구성 요소가 아닌 가장 바깥쪽 컨테이너 구성 요소를 참조합니다. 관련 추천
아주 간단한 예시를 통해 React.js 고차 컴포넌트의 개념을 이해해보세요
위 내용은 React 고차 컴포넌트 예제 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!