99
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

エーピーコミュニケーションズAdvent Calendar 2018

Day 9

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

Last updated at Posted at 2018-12-08

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
<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

99
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
99
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?