Help us understand the problem. What is going on with this article?

React 16.6の新機能、React.lazyとReact.Suspense を使った非同期処理

React v16.6 から利用可能になったReact.lazyならびにSuspenseを早速使用してみました。
この機能の嬉しいところは非同期処理時におけるコンポーネントの扱いが非常に楽になるということです。

レガシーな実装方法

この機能が追加される以前は非同期で処理を行う際にローダーを表示して処理が終了したら結果を画面に表示するといった実装する時に、以下のような方法を採用していました。

  • 処理中かどうか判断するステート isExecuting を用意する。
  • 処理開始時にisExecutingをtrueにする
  • isExecutingがtrueの時に「Please wait...」というテキストを表示
  • 処理完了時に結果を表示

つまり、ステートが変更されたらコンポーネントをレンダリングするという、Reactの仕組みに則って実現させるという方法になります。

コードに起こすと以下のような感じです。以下の例ではsetTimeoutで5秒間待っている間は「Please wait...」と表示して、完了したら「Done!」という文言を表示するという単純な例です。

App.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <MyComponent/>
        </header>
      </div>
    );
  }
}

export default App;
MyComponent.js
import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isExecuting: false,
      result: ''
    }
  }
  componentDidMount() {
    this.timeout(5000);
  }
  render() {
    return (
      <div>{this.state.result}</div>
    )
  }
  timeout(msec) {
    this.setState({isExecuting: true, result: 'Please wait...'});
    setTimeout(() => {
      this.setState({isExecuting: false, result: 'Done'});
    }, msec);
  }
}

export default MyComponent;

React.lazyおよびReact.Suspenseを使った実装方法

React.lazy()

ざっくりいうと遅延ロード用のコンポーネントをimportするための機能です。この方法で読み込んだコンポーネントをReact.Suspenseを使ってfallbackの設定などができます。

React.lazy()を使ったインポート方法
const LazyComponent = lazy(() => import('./LazyComponent'));

React.Suspense

React.Suspenseは遅延ロード用のコンポーネントをラップするコンポーネントで、このコンポーネントを使ってfallbackの設定をすることができます。

<Suspense fallback={<div>ロード完了まで表示させたい内容</div>}>
    <LazyComponent>
</Suspense>

全体のコード

以下が通しで実装したコードです。

App.js
import React, { Component, lazy, Suspense } from 'react';
// 遅延ロードしたいコンポーネントを呼び出す
const LazyComponent = lazy(() => import('./LazyComponent'));

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <Suspense fallback={<div>Please wait...</div>}>
            <LazyComponent/>
          </Suspense>
        </header>
      </div>
    );
  }
}
export default App;
LazyComponent.js
import React, { Component } from 'react';

let result = null;
const timeout = (msec) => new Promise(resolve => {
  setTimeout(resolve, msec)
});

const LazyComponent = () => {
  if (result !== null) {
    return (
      <div>{result}</div>
    )
  }
  throw new Promise(async(resolve) => {
    await timeout(1000);
    result = 'Done'
    resolve();
  })
};

export default LazyComponent;

簡単なコードなので実感が湧きにくいですが、ステートを使わない分かなりスマートに記述することが可能になります。

ちなみに、これらの機能はサーバーサイドレンダリングでは使えないようで、今後のアップデートで実装されるのかもしれませんが、公式ドキュメントではサーバーサイドで使う場合にはLoadable Componentというものが推奨されています。

出典:
React v16.6.0: lazy, memo and contextType

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away