23
9

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 1 year has passed since last update.

React 18のSuspenseを使うにあたって、fallbackのスタイリングを考える

Last updated at Posted at 2022-04-03

この記事の概要

2022年3月29日、Reactのv18.0がリリースされましたね。

公式ドキュメントの他、少し前の @uhyo さんの記事に改めて目を通していました。

上記の記事によれば大切なのは「とにかくSuspenseを理解する」だそうです。
私はデザイナーですから、スタイリング観点でいくらか考えてみました。

fallbackでよくありそうなこと(予想)

今後はこんな感じで書かれることが多くなるだろうと思っています。

const SomePage = () => {
  return (
    // 何かしらのコード
    <div className='some-class'>
      <Suspense fallback={<FallbackComponent />}>
        <SomeComponent />
      </Suspense>
    </div>
  )
}

こう書いた場合FallbackComponentが表示されている際のスタイルが意図通りにならないかもしれません。
(問題無い場合もあると思いますが)

例えばSomeComponentの描画が終わったとき、このようになっていて欲しいとします。

描画完了

SomeComponent自体はただのリストで、background-colorをつけたいのは今回がたまたま。
そのためsome-classによってbackground-color(付随するpaddingborder-radiusも)を与えたという設定です。

一見良さそうですが、fallbackにも背景色がついてしまいます。

実際に表示されるfallback 実現したいfallback

ここでパッと浮かぶのは次のようなコードでしょうか

const SomePage = () => {
  return (
    // 何かしらのコード
    <Suspense fallback={<FallbackComponent />}>
      <div className='some-class'>
        <SomeComponent />
      </div>
    </Suspense>
  )
}

SomeComponentにだけsome-classを与えたいのだから、当然と言えば当然ですね。
しかしこれはこれで問題です。

実際に表示されるfallback 実現したいfallback

左の方が余白が詰まっています。(この例だと大したこと無い話ですが……。)
今回はfallbackには何もクラスが当たっておらず、かつコンポーネント自体に余白を持たせるのはバッドプラクティスのため、こういった表示になってしまいました。

ローディング中のUIで、レイアウトシフトが起きたり明らかに大きさがおかしかったりするのは割と見かけます。
デザイナー、エンジニア、どちらの守備範囲からも微妙に外れる感は分かるのですが……抜かりなく提供したいと筆者は考えています。

上記の解消方法

現状浮かんでいるのは以下の3つです。

  1. レイアウト用ユーティリティクラスを作っておく
  2. レイアウト用コンポーネントを作っておく
  3. fallback用コンポーネントはclassNameなどを受け取れるようにしておく

1と2はイメージしやすいと思います。

レイアウト用ユーティリティクラス
const SomePage = () => {
  return (
    // 何かしらのコード
    <Suspense fallback={<div className='mt-1'><FallbackComponent /></div>}>
      <div className='some-class'>
        <SomeComponent />
      </div>
    </Suspense>
  )
}
レイアウト用コンポーネント
const SomePage = () => {
  return (
    // 何かしらのコード
    <Suspense fallback={<Margin top={1}><FallbackComponent /><Margin>}>
      <div className='some-class'>
        <SomeComponent />
      </div>
    </Suspense>
  )
}

だいたい上記のようになると思います。

議論が起きそうなのは3でしょうか。
「コンポーネントの責務を逸脱するので受け取れない方が良い」という意見はあるはずです。
筆者は個人開発だったらclassNameを渡せるようにしちゃうケースが多いのですが、チームでとなると微妙ですね。

いずれにせよ「fallback用コンポーネントをそのままfallbackに渡すとスタイル崩れが起きるかもしれない」と認識してスタイル設計に臨むのが良いのかなと思っています。


最後まで読んでくださってありがとうございます!
Twitterでも情報を発信しているので、良かったらフォローお願いします!

23
9
2

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?