😄
[Output]useDeferredValueを使ってみた。
内容
Reactのドキュメントをざっくり見ていたときに、気になったfooksがあったので勉強がてら実装をしてみました。
環境
- React
- TypeScript
- React Query
useDeferredValueとは
[useDeferredValue – React]
useDeferredValue
は、UI の一部の更新を遅延させるための React フックです。
引数に遅延させたい値をいれることができます。
初回時には、渡した初期値になるのでレンダリングが重複することはなさそうです。
基本的にsuspenseと一緒に使うものと記載があります。
またSuspenseとuseDeferredValueどちらも、React Queryなどのデータフェッチライブラリと組み合わせて使用するのが一般的とあるので、今回はReact Queryを使用して実装をしてみます。
本題(実装)
完成コード
Search.tsx
import { useDeferredValue, useState, Suspense } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import SearchResult from "./SearchResult";
const queryClient = new QueryClient();
const Search = () => {
const [query, setQuery] = useState<string | number>("");
const deferredQuery = useDeferredValue(query);
return (
<QueryClientProvider client={queryClient}>
<label>
Search Data:
<input type="text" onChange={(e) => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Loading...</h2>}>
<SearchResult query={deferredQuery} />
</Suspense>
</QueryClientProvider>
);
};
export default Search;
react-queryを使用するためにQueryClientProvider
で要素をラップします。
SeachResult.tsx
import { useQuery } from "@tanstack/react-query";
interface SearchResultInterface {
query: string | number;
}
interface DataInterface {
body: string;
id: number;
title: string;
userId: number;
}
const API_URL = "https://jsonplaceholder.typicode.com/posts";
const fetchPosts = async (): Promise<DataInterface[]> => {
const response = await fetch(API_URL);
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
};
const SearchResult = ({ query }: SearchResultInterface) => {
const { data, error, isLoading } = useQuery<DataInterface[], Error>({
queryKey: ["posts"],
queryFn: fetchPosts,
});
if (!query) return null;
if (isLoading) return <h2>Loading...</h2>;
if (error) return <h2>Error: {error.message}</h2>;
const filteredData = query
? data?.filter((item) => item.body.includes(String(query)))
: [];
return (
<>
{filteredData && filteredData.length > 0
? filteredData.map((item) => (
<div key={item.id}>
<h3>{item.title}</h3>
<p>{item.body}</p>
</div>
))
: query !== "" && <h2>No Search Data</h2>}
</>
);
};
export default SearchResult;
useQueryで状態を管理し、propsで渡したqueryに応じてデータをソートしています。
これで非同期コンポーネントとして扱え、恩恵が受けれた?かもしれないです。
まとめ
実際コードを実行してみると、特に恩恵を受けた感じはありませんでしたが、そもそもデータ量が少ないのでわかりにくかったかもしれないです。もっと大きなデータを扱うときになったら再度使用してみようと思います。
Discussion
有益な情報ありがとうございます!