React18のSuspense新機能を簡単に説明する
React18のSuspense新機能とは
こんにちは。UdemyにてReact18の新機能について学習したのでアウトプットとして記事に残します。筆者は業界未経験であり至らぬ点があるかと思いますが、間違い等あれば遠慮なくご指摘頂ければと思います。
↓学習した講座↓
Suspenseとは
リファレンスでは次のとおり説明されています。
サスペンスを使用すると、コンポーネントはレンダーの前に何かを「待機」できます。現在、サスペンスは 1 つのユースケースのみをサポートしています:React.lazy を使ってコンポーネントを動的に読み込む。将来的にはデータの取得のような他のユースケースもサポートされるでしょう。
説明は少し抽象的でやや理解に苦しむ方が多いと思いますが、ひとまず「レンダリングが完了するまでに何かできるんだな🤔」という解釈で問題ありません。また後半の説明についてですが、Suspense自体はReact18で追加された機能ではありません。React18ではあくまでSuspenseの新機能が追加されたことになります。
Suspenseの新機能
今回追加されたSuspenseの新機能はリファレンスでは次のとおり説明されています。
サスペンスにより、コンポーネントツリーの一部がまだ表示できない場合に、ロード中という状態を宣言的に記述できるようになります:
<Suspense fallback={<Spinner />}> <Comments /> </Suspense>
サスペンスにより、「UI ロード中状態」というものが、React のプログラミングモデルで宣言的に記述可能な主要コンセプトに昇格します。その上により高レベルな機能を構築していけるようになります。
上記の場合Comments コンポーネントのレンダリングが完了するまでの間、Suspenseによって「ロード中」のような表現をHTML風に記述できるというものです。ロード中に表示するものはfallback部分で記述することになります。
Suspenseの使用方法
まずはプロバイダーを設定します。Reduxあたりを触ったことがある方は「ああそういう感じね!」と感じるのではないでしょうか。
import SampleComponent from './component';
import { Suspense } from 'react';
function App() {
return (
<Suspense fallback={<p>全体ロード中です</p>} >
<SampleComponent/>
</Suspense>
);
}
export default App;
Suspenseの機能を有効にしたいサンプルコンポーネント<SampleComponent/>を<Suspense>タグで囲うだけです。fallbackオプションには<SampleComponent/>のレンダリングが完了するまでに画面に表示したいものを渡します。ここでは「<p>ロード中です</p>」を渡しているため、レンダリングが完了するまでクライアントには「全体ロード中です」と表示されることになります。
しかしSuspenseはあくまでレンダリングが完了するまでのサポートであって、エラーに対してのサポートは行われていません。
そこで、エラーに対してもサポートできるよう別途Error Boundaryライブラリを導入していきます。
yarn add react-error-boundary
インストール後、以下のように記述します。
import SampleComponent from './component';
import { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
function App() {
return (
<ErrorBoundary fallback={<p>エラーです</p>}>
<Suspense fallback={<p>ロード中です</p>} >
<SampleComponent/>
</Suspense>
</ErrorBoundary>
);
}
export default App;
記述方法はSuspenseと似ており、エラーをキャッチしたいコンポーネントを<ErrorBoundary>タグで囲います。ここでもfallbackオプションにはエラーの際に表示したいものを渡します。ここでは「<p>エラーです</p>」を渡しているため、エラーの際は画面に「エラーです」と表示されることになります。
これでレンダリング・エラー両者に対応することができました。
Suspense新機能の利点
宣言的な記述
今までレンダリングされている間(APIを利用してデータを取得しているときなど)のロード画面はif文や演算子を用いて記述することがあったと思います。
import SampleComponent from './component';
function App() {
const [isLoading, setIsLoading] = useState(false);
return (
{isLoading && <p>...ロード中です</p>}
<SampleComponent/>
);
}
このような記述ではjsx内にロジックを記述することになり、どのようなUIが表示されるのか直感的に認識しづらくなります。Reactの「宣言的な View」という理念にもある通り、UIとロジックは分けて記述する方が望ましいです。そのような意味でSuspenseはjsx内に<Suspense>タグを用いて宣言的に記述することに成功していると言えます。
他にも同じくReact18の新機能であるトランジションと組み合わせることにより快適なUXを提供できるなどもありますが、トランジションについては別途記載したいと思います。
終わりに
ここまで読んで頂きありがとうございました。簡単な説明ではありますがSuspenseでできることがイメージできたかと思います。間違っていることや捕捉事項があればコメントやTwitter(@hiro)に遠慮なくご指摘頂ければと思います。
Discussion