現在QiitaではQiita Engineer Festa 2022が開催中です。当記事もエントリーしております
最近React18がリリースされたようです
React18に関しては@uhyoさんに非常に参考になる記事を投稿していただいてます
ただ、いまいちuseTransitionとuseDefferedValueについて理解できていませんでした
そこで今回はこれらのHooksについて自分で内容をまとめてみたいと思っています
ちなみに、この記事ではconcurrent modeがリリースされるかもしれないが未定と書かれていますが、現在の正式リリースでは「mode」という考え方自体がなくなり、concurrent modeのみが標準として組み込まれています
useTransitionとuseDefferedValueの具体的な使い方
まずはそれぞれの使い方に関して確認しましょう
useTransiton
以下のコードはinputのテキスト入力後、レンダリングに関するリソースに余裕のある段階でコンポーネントが再レンダリングされるという仕様になっています
つまりテキスト入力によるstate変更で引き起こされたpostsの再レンダリング優先度を低くするということです
export default function Home() {
const [isPending, startTransition] = useTransition();
const [keyword, setKeyword] = useState('');
// Web APIからキーワードでフィルターした投稿一覧を取得
const filteredProducts = filterKeyword(keyword);
const updateKeyword = (e) => {
startTransition(() => {
setKeyword(e.target.value);
});
}
return (
<div id="app">
<input type="text" onChange={updateKeyword} />
{isPending && <p>Updating List...</p>}
<PostsList posts={filteredPosts} />
</div>
);
}
useDeferredValue
続いてuseDeferredValueです
以下のコードは非同期で受け取ったPropsであるpostsを遅延してレンダリングを行っています
propsから値を受け取った時点ですぐにレンダリングするのはなく、postsをレンダリングする優先度を他のコンポーネントの描画優先度より下げる役割を担っています
function PostsList({ posts }) {
const deferredPosts = useDeferredValue(posts);
return (
<ul>
{deferredPosts.map((post) => (
<li>{post}</li>
))}
</ul>
);
}
useTransitionとuseDefferedValueの違い
上記の例で示した通り「useTransition」はstateを更新する処理をwrapして遅延させるのに対し、「useDeferredValue」はstateの値をwrapして変更を遅延させています
以下基本的な使い分けに関しての結論です
keywordのように更新中のstateを読み込む必要があるのであればuseTransitionを、逆に読み込む必要がないのであればuseDeferredValueを使えば良いのではないかと思っています
それでは全ての非同期処理で受け取る値をuseTransitionやuseDeferredValueでwrapすればいいのではないかという話になるのですが、それは控えた方が良さそうです
先ほども述べたように「レンダリングに関するリソースに余裕のある段階」なので、非同期処理によるstate管理が煩雑になることが考えられます
あるときはstateが更新されているが、あるときはされていないというようなバグを引き起こさないためにも頻繁に使うようなhooksではなさそうです
あくまでもパフォーマンスチューニングという観点で、stateの変更を遅延させることが適切かどうか判断してから使用するようにしましょう