Runner in the High

技術のことをかくこころみ

Reactの`use`とmoizeを組み合わせるといい感じ

最速攻略記事によると、Reactのuseはキャッシュと組み合わせる必要があらしい。

というわけでmoizeを使ってみたらいい感じだった。

"use client";
import { Suspense, use, useState } from "react";
import moize from "moize";

export default function Home() {
  return (
    <main>
      <h1>Suspense</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <Waiter />
      </Suspense>
    </main>
  );
}

const waiting: () => Promise<string> = moize(
  () =>
    new Promise((resolve) =>
      setTimeout(() => {
        resolve("hello world");
      }, 500)
    )
);

const Waiter = () => {
  const [counter, updateCounter] = useState(0);
  const value = use(waiting());

  return (
    <>
      <button onClick={() => updateCounter((c) => c + 1)}>increment</button>
      <div>Count: {counter}</div>
      <div>Waited: {value}</div>
    </>
  );
};

動作確認

state更新の際にはuseに渡されているPromiseは評価されないので、レンダリングが部分的になっている。

waiting関数の評価は初回のみ。

キャッシュあり

ちなみにmoizeでキャッシュしないと、state更新のタイミングでuseに渡されたwaiting関数も毎回評価されるので再レンダリングされてしまう

キャッシュなし

しかし、moizeをただ単に使うだけだと、キャッシュの管理やinvalidationなどの機構が不十分なため実用性には欠ける。

そういう意味では巷にあるSuspenseサポート系のライブラリを使う方がよい。

追記

2023年8月時点ではReactのmainブランチにCache APIでラップされたfetchが実装されているため、将来的にはclient-side fetchでもmoizeなどのキャッシュライブラリなしでUse APIを楽に使える可能性がある。

izumisy.work