9
6

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.

バージョン2.0.1でSWRの型が便利になった

Last updated at Posted at 2023-01-22

はじめに

SWRはバージョン2.0.1でSuspenseモードにおけるdataの型推論の結果が変化しました。パッチリリースですが、長年苦しんでいた問題が解決されたので紹介します。

2.0.0以前の世界

ReactにSuspenseが登場してからデータ取得はより宣言的に書くことができるようになりました。
元々SWRを用いてデータ取得を行うコンポーネントは以下のように書かれていました。以後fetcherの返り値はPromise<string>とします。

export const Sample = (): JSX.Element => {
  const { data } = useSWR(key, fetcher);
  
  if (!data) {
    return <Loading />;
  }
  
  return <>{data}</>;
};

そして、Suspenseが登場してからは以下のように書けるようになりました。

export const Sample = (): JSX.Element => {
  const { data } = useSWR(key, fetcher, {
    suspense: true,
  });

  return <>{data}</>;
};

export const App = (): JSX.Element => {
  return (
    <Suspense fallback={<Loading />}>
      <Sample />
    </Suspense>
  );
};

dataが取得できていなかったら(undefinedだったら)<Loading />を返すような命令的なコードから親コンポーネントで<Sample />がSuspenedされていたらfallbackを表示させるような宣言させるコードに変わっています。
この例ではuseSWRからdataが返される時にはfetcherが解決済みになっているはずなので、dataの型はstringとなって欲しいです。しかし、実際はstring | undefinedとなります。この結果はこの例では問題になりませんが、取得したデータを他のコンポーネントに渡すときや、プリミティブで無いデータを扱っているときにdataundefinedではないことを確認する分岐が必要になってしまいます。
このことはswrのリポジトリでも議論に挙げられることが多く、例えば以下のissueで議論されていました。

2.0.1で変更された型

先日のパッチバージョンアップではその問題が解決しました。

export const Sample = (): JSX.Element => {
  const { data } = useSWR(key, fetcher, {
    suspense: true,
  });

  return <>{data}</>;
};

export const App = (): JSX.Element => {
  return (
    <Suspense fallback={<Loading />}>
      <Sample />
    </Suspense>
  );
};

先ほどと同じコードなわけですが、dataの型はstring | undefinedからstringに推論されるように変更されました。
これによって毎回dataundefinedでは無いことを確認しなくて済むようになったのでとても嬉しい変更です。ただし、useSWRの第三引数options{ suspense: true }としなければこの推論にならないので注意してください。

疑問

私の環境ではSuspenseモード下で条件付きフェッチを行ったとしてもdataの型はstringに推論されてしまいました(実行するとエラーが出ます)。
ドキュメントに従うとdataの型はstring | undefinedになると考えていたので疑問でした。
先ほどのissueを読むとSuspenseが有効な時はdataundefinedにならないという制限だけではなく、keyがFalsyな値ではないこと、fetchernullではないような制限が必要と書かれていました。SuspenseモードではPromisethrowするもしくは解決後の値を返すだけを想定していて、これに当てはまらない条件付きフェッチではエラーを出さざるを得ないのではいかなと考えています。
今後この周りがどのように変化していくかとても楽しみです。

9
6
0

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?