1

実験的な新しい React 機能Suspense for data fetching を使用しようとしています。

useApiこれは、(サスペンスを正しく理解している場合)fetch呼び出しの結果を返すか、サスペンダーの約束をスローする単純なフックです。(文書化された例をわずかに変更)

function useApi(path) {
  const ref = React.useRef({ time: +new Date() });
  if (!ref.current.suspender) {
    ref.current.suspender = fetch(path).then(
      data => ref.current.data = data,
      error => ref.current.error = error,
    );
  }
  if (ref.current.data) return ref.current.data;
  if (ref.current.error) return ref.current.error;
  throw ref.current.suspender;
}

私はこのフックを次のように単純に使用しています:

function Child({ path }) {
  const data = useApi(path);
  return "ok";
}
export default function App() {
  return (
    <Suspense fallback="Loading…&quot;>
      <Child path="/some-path" />
    </Suspense>
  );
}

それは決して解決しません。

useRef問題は、それが想定どおりに機能していないことだと思います。

ref をランダムな値で初期化すると、その値は保持されず、代わりに別のランダムな値で再初期化されます。

const ref = React.useRef({ time: +new Date() });
console.log(ref.current.time)
1602067347386
1602067348447
1602067349822
1602067350895
...

suspenderをスローすると、useRefすべての呼び出しで が再初期化されるという奇妙なことがあります。

throw ref.current.suspender;

その行を削除するとuseRef意図したとおりに機能しますが、明らかにサスペンスは機能しません。

私がそれを機能させる別の方法は、次のように、React の外部である種のカスタム キャッシングを使用する場合です。

const globalCache = {}
function useApi(path) {
  const cached = globalCache[path] || (globalCache[path] = {});
  if (!cached.suspender) {
    cached.suspender = ...
  }
  if (cached.data) ...;
  if (cached.error) ...;
  throw cached.suspender;
}

これでも機能しますが、コンポーネント固有のデータをキャッシュするという点で React 自体が提供するものを使用したいと思います。

useRefサスペンスでの作業方法について、何かが欠けていますか?

再現: https://codesandbox.io/s/falling-paper-shps2

4

2 に答える 2