Next.js で React.Suspense を使った時の ReactDOMServer does not yet support Suspense エラーが出た

📆January 04, 2021🔖 Next.js

Recoil の試し切りをしていたところ、非同期通信のところでハマったのでメモ。

function ResultsSection() {
  return (
    <React.Suspense fallback={<div>Loading...</div>}>
      <QueryResults />
    </React.Suspense>
  );
}

export default ResultsSection;

(QueryResults は非同期通信で取得した値を描画するコンポーネントです)上記のようなコードで、fetch 中は Loading... というコンポーネントを表示したかったのですが、以下のように ReactDOMServer does not yet support Suspense というエラーが出てしまいました。

ReactDOMServer does not yet support Suspense
ReactDOMServer does not yet support Suspense

これは、React.Suspense がまだ SSR に対応してないことによるエラーでした。今回は、Recoil の fetch 部分で React.Suspense が使用したかったのですが、調べたところ以下の Issue で全く同じことが議論されており、対応策として、useRecoilValueLoadable を使えば良いとのことでした。

https://github.com/facebookexperimental/Recoil/issues/722

結論、React.Suspense を使用せず、以下のようなコードにすれば OK 。

function QueryResults() {
  const queryResults = useRecoilValueLoadable(myQuery);
  switch (queryResults.state) {
    case "hasValue":
      return <div>{queryResults.contents.id}</div>;
    case "loading":
      return <div>Loading...</div>;
    case "hasError":
      throw queryResults.contents;
  }
}

function ResultsSection() {
  return <QueryResults />;
}

export default ResultsSection;

useRecoilValueLoadableLoadable オブジェクトを返却します。Loadable オブジェクトは、3つのいずれかで、Switch 文にある通りですが、fetch 中、fetch 成功、fetch 失敗のいずれかの状態を表すオブジェクトです。(型定義部分のスクリーンショットを添付)

Loadble オブジェクトの型定義
Loadble オブジェクトの型定義

Loadable.state で状態が取れるので、状態によってコンポーネントの出し分けを自前で実装すれば良いというわけですね。ちょっとハマったのでメモでした。