Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

ステート更新を伴わないなら useTransition を使うべきではない

※React公式の見解ではありません。公式ドキュメントの文言などをもとに推察した記事になります。

「useTransitionはどう使うべきものなのか?どう使ってはいけないのか?」を考察したのでまとめる。

useTransition は「ステートの遷移」を表現するべき

useTransitionは(複数の) ステートの遷移を扱うフック だ。

const [isPending, startTransition] = useTransition();

startTransition(() => {
  setSomeState(newValue);
});

someState が newValue へ遷移している途中なら isPending は true になる。

ステートの遷移 = 画面遷移

Reactは UI=f(state) という原則を持つ。なので、ステートの遷移=画面遷移 とも言い換えられる。stateが変化した場合、UIも(基本的に)変化するからだ。

これは逆に言えば、画面変化を伴わないなら useTransition のユースケース外 、ということでもある。

単なるローディング処理に使うべきでない

上の定義に従うと、例えばファイルダウンロードのような、最終的に画面が変化しないユースケースは トランジションに該当しない

// ↓こういう使い方はトランジションに該当しないため推奨されない
const [isDownloading, startTransition] = useTransition();

const download = () => startTransition(async() => {
  await downloadFile(); // state変化を伴っていない
});

この操作は「ある画面から別の画面に段階的に遷移」に該当していない。ダウンロードが完了したら元の状態に戻るからだ。

こういう時は単純に isLoading ステートを定義すれば十分 だ。

const [isDownloading, setIsDownloading] = useState(false);

const download = async() => {
  setIsDownloading(true);
  await downloadFile();
  setIsDownloading(false);
};

Q. コレって公式見解なの?

大事なことだがが、上に書いたのは 公式見解ではない。が、ドキュメントを読む限りは それを想定していると思われる

例えば useTransition – React の引数の項目にはこういう記述がある。

action: 1 つ以上の set 関数を呼び出して state を更新する関数。

また、React v18.0 - 新機能:トランジションにはこのように書かれている。

トランジションとは React における新たな概念であり、緊急性の高い更新 と高くない更新 を区別するためのものです。

  • トランジションによる更新は UI をある画面から別の画面に段階的に遷移させるものです。

ココからも、画面遷移を伴わなければトランジションと呼べないと思われる。

ただ、現時点ではlinterによる制約などもなく、画面遷移を含まない(set関数を呼び出さない)"トランジション"も書ける。しかし、今後のReactのアップデートによってset関数を1つ以上含んでいることを前提とした最適化が行われる可能性は全然ある。なので、今のうちにset関数を含まない場合はuseTransitionを使わないようにしておくほうがよさそうだ。

おわり

過去には単に「async関数の実行中ステート」のためにuseTransitionを使っていたが、改めてドキュメントを読んで整理してみて、今後は控えていこうと思った。みんなも気をつけよう。いや、気をつけなくても良いかもしれない。それは自分で決めよう。