Skip to content

Instantly share code, notes, and snippets.

@mizchi
Last active July 9, 2020 08:01
Show Gist options
  • Save mizchi/eb043af6667b60d5f8a0862cd16b39ea to your computer and use it in GitHub Desktop.
Save mizchi/eb043af6667b60d5f8a0862cd16b39ea to your computer and use it in GitHub Desktop.
テストから読み解くReact Suspense の使い方

TL;DR

// Create Lazy Component
const LazyComponent = React.lazy(() => import('./SomeOtherComponent'));

ReactDOM.hydrate(
  <React.unstable_Suspense fallback="loading">
     <LazyComponent />
  </React.unstable_Suspense>
  , element
);

await LazyComponent;
// Done!

React.lazy で作った非同期コンポーネントを React.Suspense で囲むと非同期処理が行われる。

びっくりするのは、 React.lazy で作ったコンポーネントを await できる (内部的には then が実装してある)

await を待つとDOMへの適用処理を待って表示できる。読む限りはこのテストは ReactDOMServer ではなく ReactDOM + jsdom on Node.js なのだが、jsdom なしで動くようにできるかは不明。

SSRを実装する人は内部の非同期処理の promise をかき集めて、Promise.all することになりそう

元のコード

packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js

 it('should be able to use lazy components after hydrating', async () => {
    async function fakeImport(result) {
      return {default: result};
    }

    const Lazy = React.lazy(
      () =>
        new Promise(resolve => {
          setTimeout(
            () =>
              resolve(
                fakeImport(function World() {
                  return 'world';
                }),
              ),
            1000,
          );
        }),
    );
    class HelloWorld extends React.Component {
      state = {isClient: false};
      componentDidMount() {
        this.setState({
          isClient: true,
        });
      }
      render() {
        return (
          <div>
            Hello{' '}
            {this.state.isClient && (
              <React.unstable_Suspense fallback="loading">
                <Lazy />
              </React.unstable_Suspense>
            )}
          </div>
        );
      }
    }

    const element = document.createElement('div');
    element.innerHTML = ReactDOMServer.renderToString(<HelloWorld />);
    expect(element.textContent).toBe('Hello ');

    ReactDOM.hydrate(<HelloWorld />, element);
    expect(element.textContent).toBe('Hello loading');

    jest.runAllTimers();
    await Lazy;
    expect(element.textContent).toBe('Hello world');

を読む限りわかること

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment