※この記事はuse APIへの自分の理解と、実際にコードを起こして実験した結果を記しただけの 考察記事 です。正しさは保証されていません。「多分こういうマインドセットを持ってるとええんやな〜」くらいの温度感でお楽しみください。
導入: Throw a Promiseテクと use API はどういう関係なのか?
react 19から導入されたuse APIによって、reactは自然にPromiseを扱えるようになりました。 しかし、react18まではPromiseをthrowすることでレンダリングを中断するやり方も提供されていました。2つはユースケースがとても似通っていて混乱します。
このユースケースが似た2つ(use APIとThrow a Promise)の関係は、uhyo さんが記事でわかりやすくまとめています。
ちなみに、Suspenseを前提とする以上、
useの中身は良く知られた「Promiseをthrowする」実装になっています。ただし、useは生でPromiseをthrowするのではなく、Suspense ExceptionというErrorオブジェクトでラップしてthrowするようです。これは開発者をなるべく混乱させないための配慮でしょう。
つまり、Throw a Promise を使った洗練された API が use API とのことです。また、「"Throw a Promise"をdeprecatedにしてuse APIを推奨していこう」というissueも立てられています (当該issue)。このことからも、今後は開発者が Throw a Promise を自らする必要はなくなっていくと思われます。
でも、use API が内部で Promise を throw しているとはどういうことなんでしょうか? 実際に書けるんでしょうか? そう思ってトライしてみたのが本記事になります。
use API を自作してみる
use API の要件としては以下になるはずです。
- Promiseを受け取る
- Promiseがresolveしたらその値を返す
- PromiseがまだresolveされてなかったらPromiseをthrowする
これを非async関数で実装するには、resolveされた値を保存する記憶領域を外部に確保する必要があります。幸いにもJSにはWeakMapというものがあるので、それを使いましょう。
const dataMap = new WeakMap(); // resolveされた値を保存しておく場所 const use = (promise) => { promise.then((data) => { dataMap.set(promise, data); // resolveされたら保存する }); const data = dataMap.get(promise); if (!data) throw promise; // dataがまだない=resolveされてなかったらpromiseをthrowする return data; // dataがある=resolve済みの場合はdataを返す };
これを使って実際に実装してみたコードがこちらになります。
ちゃんとreact19のuse APIと同じような動きが実装できています。
(uhyoさんがいってる「Suspense Exceptionでラップしてる」の部分はよくわかりませんでした。有識者求ム)
まとめ: 今後は use API だけ使えば良さそう
ここまでの実験によって、throw a Promiseによってレンダリングの中断・再開を実装するテクニックは、use API によってより洗練されたインターフェイスとなったことが分かりました。
use API で大体のユースケースはカバーできると思うので、今後は基本的に use API だけ使えば良さそうです。




