LoginSignup
11
3

More than 1 year has passed since last update.

React conf 2021 の気になったテーマをまとめてみた(Suspense / Automatic batching / React without memo )

Last updated at Posted at 2021-12-11

12/9 に React conf 2021 が開催されました!!

React Suspense

やはり React 18 のメインコンテンツはSuspenseですよね。
ついにSuspenseが使えるようになります...!!

React Suspenseとは?

今まで、非同期APIでデータフェッチした時に、下記のようなコードを書いたことはありませんか?

export const List = () => {
  const [items, isLoading] = useData(...);

  if (isLoading) return <Loading />;

  return items.map(item => (
    <li>{item.something}</li>
  ));
}

このコンポーネントでは、下記のようなことを行っています。

  • データを取得する
  • データがロード状態である時、Loadingコンポーネントの表示
  • 取得したデータの表示

しかし、下記2つは同じ場所にいる必要がありません。

  • データの取得
  • ローディング状態の処理

理由は下記のように述べられています。

  • データフェッチする時に、常にロード状態を返却する必要がある
  • 任意のコンポーネント内でデータを追加/削除などの変更があった際に、その度にローディング状態をどうするか考えなくてはいけない
    • ローディング状態どうするか問題がデータに紐付きすぎている

これらを解決するのがSuspenseです。

// 子コンポーネント(<List />)の準備ができているか検知し、できていなかったら<Loading />を表示する
export const Page = () => {
  return (
    <Suspense fallback={<Loading />} >
      <List />
    </Suspense>
  )
}

// ここでローディングなのかを知る必要がない
export const List = () => {
  const [item] = useData(...);

  return items.map(item => (
    <li>{item.something}</li>
  ));
}

もし、のchildrenが準備できていなかった場合、fallbackに定義されたコンポーネントが表示されます。
つまり、Suspenseでは、「データが準備されたか」ではなく「JSXが準備されたか」という考え方に変わったのです。

そのため、データの依存関係やコンポーネントの依存関係を考えず、スケルトンやスピナーなどの準備状態のUIを表示することができるのです。

▼ 参考

Automatic batching

今まで下記のようにset関数を3つ書いた場合、3回再レンダーが走りました。

const handleClick = () => {
  setIsFetching(false)
  setError(null)
  setFormStatus('success')
}

しかし、set関数を呼ばれる度にレンダリングするのではなく
関数の最後のみ実行されるようになります。
つまり、handleClickは1回のみのレンダリングで済むようになります!

▼ 参考

React without memo

React Forgetという研究プロジェクションによる発表です。
これはまだ進行中のプロジェクトであり、まだリリースされていないものになります。

そもそもメモ化とはなんぞ?という人は、下記記事を参考にしてください。(告知)

メモ化することで、不要な再レンダリングを減らすことができるためユーザーには良い体験を与えられます。
一方で、データの依存関係や参照の同一性を考えてメモ化しなきゃいけないため、開発者は考えることが多い上にコード量も増えていきます。

UXとDX...この両方がよい状態にするにはどうすれば良いでしょう。
そこで、メモ化の方法を再検討したそうです。

大前提

useMemouseCallbackは、propsstateの入力を受け取って、
UIやエフェクトなどに出力するための関数に過ぎません。

useMemoの再検討

const filtered = useMemo(
  () => getFiltered(todos, visibility),
  [todos, visibility]
)

useMemoがしていることは、キャッシュされている前回のレンダリングの値と比較して、
値に変更があったら再実行、値に変更がなかったらそのままにしているだけです。

let hasVisibilityChanged, hasTodosChanged, memoCache;

let filtered;
if (hasVisibilityChanged || hasTodosChanged) {
  filtered = memoCache[1] = getFiltered(todos, visibility)
} else {
  filtered = memoCache[1]
}

useCallbackの再検討

const handleChange = useCallback(
  todo => setTodos((todos) => getUpdated(todos, todo)),
  []
)

useCallbackにおいても、前回の値がなかったら生成してキャッシュさせてあげるだけです。

const handleChange =
  memoCache[0] ||
  (memoCache[0] = (todo) => setTodos((todos) => getUpdated(todos, todo)));

このような仕組みを用いて、関数や値、さらにはjsxなどを自動的にメモライズしてくれる仕込みを
未来のReactに導入するみたいです!! :heart_eyes: :heart_eyes: :heart_eyes:

すでにでdemoがあります。

▼ demo映像からのリンク

期待大ですね!!この研究がうまくいくことを願っています。


これらはReact Confのほんの一部でしかありません!!
こちらに全動画がまとまっているので、ぜひチェックしてみてください:qiitan:

11
3
1

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