【入門編】 useTransitionと副作用の優先順位付け – React実践ガイド

こんにちは!Reactの学習、毎日お疲れ様です。

画面を作っていて、「お、なんか今のボタンを押したとき、ちょっとだけ画面がカクッとしたぞ……?」なんて冷や汗をかいた経験、ありませんか? 大丈夫ですよ、それ、誰もが最初に通るめちゃくちゃリアルな壁ですからね。

今日は、そんなReactの「カクつき」を鮮やかに解消してくれる、ちょっと頼もしい新時代の相棒`useTransition`についてお話しします。

難しい専門用語はなるべく置いておいて、身近な例えからゆっくり紐解いていきましょうか。

—

なぜ画面はカクついてしまうのか?

まずは敵を知ることから始めましょう。Reactが画面をカクつかせる原因、それは一言で言うと「お仕事の丸投げしすぎ」です。

想像してみてください。あなたは今、大人気のラーメン屋さんの店主です。
目の前には「早くお水が飲みたい!」と言っているお客さんがいます(これがユーザーの入力やクリックですね)。

普通なら、お水をスッと出してあげたいところですが、もしあなたが「よし、今からチャーシューの仕込み(重たいデータ処理や画面の描き直し)を始めるぞ!」と言って、脇目もふらずにブ厚い豚肉を切り始めたらどうでしょう?
お客さんはお水を欲しがっているのに、あなたはチャーシューに夢中で、お客さんはずっと待たされてしまいますよね。これが、Webブラウザで言う「画面のカクつき(フリーズ感)」の正体です。

Reactもこれと同じで、重たい処理が始まると、入力フォームへの文字入力やボタンの反応といった「今すぐやりたい大事な仕事」まで後回しにしてしまいがちなんです。

—

`useTransition`ってどんな道具?

ここで登場するのが、今回の主役である`useTransition`です。

こいつを例えるなら、優秀な「アルバイトのスタッフさん」です。

お客さんが来たら、あなた(メインスレッド)は最優先でお水を出します(UIの応答性をキープ!)。そして、時間のかかるチャーシューの仕込み(重たい状態の更新や副作用)は、
> 「それ、急ぎじゃないから、手が空いたときに裏でゆっくりやっておいて!」

と、そのアルバイトさん(`useTransition`)にそっとお願いするわけです。

これによって、画面はカクつくことなく、ユーザーはいつでもサクサク快適に操作できるようになります。最高ですよね。

—

実際のコードで動かしてみよう

百聞は一見にしかず。実際にコードを見てみましょう。
ここでは、「文字を入力すると同時に、大量のリストをフィルタリングして表示する」という、よくあるカクつきがちなシーンを想定してみます。

コピペして、お手元の環境でそのまま動かしてみてくださいね。

import React, { useState, useTransition } from ‘react’;

// わざと重たい処理を作るためのダミー関数(10000件のリストを作ります)
const createDummyList = (filterText) => {
const list = [];
for (let i = 0; i < 10000; i++) { if (filterText && !`アイテム ${i}`.includes(filterText)) { continue; } list.push(`アイテム ${i}`); } return list; }; export default function App() { const [inputVal, setInputVal] = useState(''); // 今すぐ反映させたい入力値 const [list, setList] = useState(createDummyList('')); // 重たいリストのデータ // ここがポイント!useTransitionの導入です // isPending は「今、裏でお仕事中かどうか」を教えてくれる便利な旗(フラグ)です const [isPending, startTransition] = useTransition(); const handleInputChange = (e) => {
const value = e.target.value;

// 1. 【高優先度】入力欄の文字は、一瞬たりとも遅れず今すぐ書き換える!
setInputVal(value);

// 2. 【低優先度】1万件のリストをフィルタリングする重たい処理は、
// startTransition の中に包んで、アルバイトさんにそっとお任せする!
startTransition(() => {
setList(createDummyList(value));
});
};

return (

useTransitionの体験デモ

{/ 入力フィールド /}

{/ 裏でお仕事中のときだけ、優しい合図を表示する /}
{isPending &&

🔄 裏で一生懸命リストを準備中だよ……

}

{/ リストの表示 /}

全 {list.length} 件が見つかりました

    {list.slice(0, 50).demap ? null : list.slice(0, 50).map((item, index) => (

  • {item}
  • ))}

);
}

コードのここが優しい!

1. `setInputVal(value)` は即座に実行する
ユーザーがキーボードを叩いた瞬間、入力欄の文字は一瞬の遅延もなくスーッと変わります。ここがもたつくと人間はストレスを感じるので、何よりも最優先にします。
2. `startTransition` の中身は後回しにする
1万件のデータをゴソゴソと絞り込む重たい処理は、`startTransition`の中に包みました。Reactは「お、これは急ぎじゃないんだな」と察知して、ブラウザの隙間時間(フレームの合間)を見つけてこっそり処理してくれます。
3. `isPending` で親切な演出ができる
「今、裏で頑張って準備してるよ」という状態を `isPending` が教えてくれるので、ローディング表示を出してユーザーに安心感を与えることができます。これ、実務だとめちゃくちゃ重宝するテクニックです。

—

つまずきやすいポイントと、そっと寄り添うアドバイス

ここで、初心者の頃にありがちな「あれ?」というポイントを先にお話ししておきますね。

> Q. なんで普通の `setTimeout` じゃダメなの?
>
> A. 素晴らしい疑問です! `setTimeout` でも遅延はできますが、あちらは「何ミリ秒後に実行する」という時間の予約でしかありません。一方の `useTransition` は、Reactの内部スケジューラーと深く連携して、「ブラウザが今忙しいから待って、暇になったらやって」という優先度のコントロールを行ってくれます。Reactの仕組みと一番喧嘩しない、現代のスマートなやり方なんです。

> Q. なんでもかんでも `startTransition` で包めばいいの?
>
> A. いいえ、そこは少し注意が必要です。API通信の結果を反映させるときや、入力フォームの文字そのものを変えるときは、逆に「遅れて見えてしまうとバグのように感じる(あるいはイライラする)」原因になります。あくまで「画面の描き直しが重たくてカクつくところ」に絞って使うのがコツですよ。

—

おわりに

Reactのパフォーマンス最適化と聞くと、なんだか難解な呪文を唱えなきゃいけないような気がして身構えてしまいますよね。でも、`useTransition` は、僕たち開発者が「ねえ、こっちは急ぎじゃないから後回しにしていいよ」と、Reactに優しく指示を出してあげるための、とっても人間味のある機能です。

あなたの書いたコードが、ユーザーにとって心地よい滑らかな手触りになったとき、アプリ開発はもっと楽しくなります。

今日からあなたの引き出しの一つに、この `useTransition` をそっと加えてみてくださいね。
それでは、また次回の記事でお会いしましょう!あなたの開発ライフを、心から応援しています。

コメント

タイトルとURLをコピーしました