React - 비동기 컴포넌트 렌더링 래퍼

대부분의 경우 프런트 엔드 애플리케이션은 필요한 데이터를 채우고 표시하기 위해 광범위한 서비스 및 API와 상호 작용합니다. 우리는 일반적으로 동일한 로딩 화면을 표시하고 실제로 페이지를 사용하도록 허용하기 전에 사용자가 일정 시간을 기다리게 합니다. 그러나 때때로 사용자에게 필요한 대부분의 콘텐츠는 사용할 수 있지만 사용자는 페이지의 불필요한 데이터가 로드될 때까지 기다려야 합니다. 이것은 사용자 경험 관점에서 볼 때 매우 나쁩니다.

이 시나리오를 고려하십시오. 블로그 링크를 여는 중입니다. 텍스트는 훨씬 빠르게 로드되지만 페이지는 사진과 사이드 링크가 로드될 때까지 탐색을 허용하지 않습니다. 대신 페이지에서 사진과 다른 것들이 동시에 로드되는 동안 탐색할 수 있습니다.

반응에서 이 문제를 해결하는 방법 중 하나는 구성 요소를 렌더링하기 위해 비동기 래퍼를 사용하는 것입니다. HeadingComponentParagraphComponent 두 가지 구성 요소를 사용하겠습니다.

const HeadingComponent = props => <h1>{props.data}</h1>;

const ParagaphComponent = props => <p>{props.data}</p>;


이제 두 가지 다른 API의 데이터를 표시하는 AsyncComponentHeadingComponent의 래퍼 역할을 하는 ParagraphComponent를 생성합니다.

class AsyncComponent extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      resolvedError: false,
      resolvedSuccess: false,
      data: '',
      error: '',
    };
    this.renderChildren = this.renderChildren.bind(this);
  }

  componentDidMount() {
    this.props.promise()
      .then(data => this.setState({ resolvedSuccess: true, data }))
      .catch(error => this.setState({ resolvedError: true, error }));
  }

  renderChildren() {
    return React.Children.map(this.props.children, child => (
      React.cloneElement(child, {
        data: this.state.data,
      })
    ))
  }

  render() {
    if (this.state.resolvedError) {
      return <h1>Error Encountered</h1>;
    } else if (this.state.resolvedSuccess) {
      return <div>{ this.renderChildren() }</div>;
    } else {
      return <h1>Loading...</h1>;
    }
  }
}

AsyncComponentpromise 에서 호출하는 componentDidMount 라는 소품을 사용합니다. 성공적으로 해결되면 데이터를 상태로 저장하고 거부된 경우 오류가 발생합니다. 그런 다음 렌더링 방법에서 렌더링합니다.
  • 오류의 경우 오류 구성 요소
  • 성공적으로 해결된 경우 하위 노드가 됨
  • 그렇지 않으면 구성요소를 로드함

  • 때로는 하위 구성 요소에 응답 데이터가 필요합니다. React는 자식 요소에서 직접 구성 요소를 가져오는 것을 허용하지 않으므로 React.Children.mapReact.cloneElement 와 같은 React의 내장 함수를 사용합니다. 구성 요소의 자식을 탐색하고 API의 실제 응답이 있는 propdata을 추가하여 각 자식 요소를 복제하여 자식도 응답에 액세스할 수 있도록 합니다.

    위의 모든 사항을 결합한 최종 코드

    const HeadingAPI = () => new Promise((resolve, reject) => {
      setTimeout(() => resolve('Heading'), 5000);
    });
    
    const ParagraphAPI = () => new Promise((resolve, reject) => {
      setTimeout(() => resolve('Paragraph data'), 2000);
    });
    
    const App = () => (
      <div>
        <AsyncComponent promise={HeadingAPI}>
          <HeadingComponent />
        </AsyncComponent>
        <AsyncComponent promise={ParagraphAPI}>
          <ParagaphComponent />
        </AsyncComponent>
      </div>
    );
    


    다음은 두 약속이 모두 성공적으로 해결된 시나리오를 실행하는 Codepen입니다.


    다음은 약속 중 하나가 거부될 때 시나리오를 실행하는 Codepen입니다.


    보시다시피 한 API의 실패는 다른 구성 요소의 렌더링에 영향을 미치지 않으며 사용자는 관계없이 웹 페이지를 계속 탐색할 수 있습니다. 이를 통해 사용자 경험이 크게 향상되고 구성 요소 전체에서 API 호출로 생성되는 중복 코드의 양이 줄어듭니다.

    사용자 지정 로더 및 오류 구성 요소를 제공하여 래퍼를 더 멋지게 보이게 하여 래퍼를 개선할 수 있습니다.

    좋은 웹페이지 즐겨찾기