前書き
React Queryがv4になったタイミングで、正式な名称はTanStack Query
になりましたが、この記事内ではReact Query
と呼ばさせていただきます。
公式ドキュメント:
どんなwebシステムでもフロントからサーバーへのデータの取得、修正削除などのリクエストは必ず発生します。
React Query
使用することで、何がどう便利になったのか、簡単なサンプルを見て、体感しましょう。
サンプル少し長いので最後まで付き合っていただけると幸いです。
サンプル
簡単なリストデータを取得することを想定しているサンプルになります。
- axiosで書いてますが、fetchでも使い方同じです。
async function requestList() {
const { data } = await axios.get("/api/list");
return data;
}
4行のコードを書くだけで、サーバーからデータの取得はできます。
次はこのリクエストをフック
にして、使い勝手を改善します。
function useListQuery() {
const [data, setData] = React.useState([]);
React.useEffect(() => {
(async () => {
const { data } = await axios.get("/api/list");
setData(data);
})();
}, []);
return {
data,
};
}
function List() {
const { data } = useListQuery();
return (
<div>
{data.map((item) => {
return <div>{item}</div>
})}
</div>
);
}
ここまで書いたら、一見良さげですが
リクエスト送った後のエラー、ローディング処理はまだのため、追加しておきます。
function useListQuery() {
const [data, setData] = React.useState([]);
const [isLoading, setLoading] = React.useState(false);
const [error, setError] = React.useState();
React.useEffect(() => {
(async () => {
setLoading(true);
try {
const { data } = await axios.get("/api/list");
setData(data);
} catch(e) {
setError(e);
}
setLoading(false);
})();
}, []);
return {
data,
isLoading,
error,
};
}
以上、これで良くあるリクエストを管理するフックが完成しました、それを実現するために25行のコードも書いてしまったのですが、
React Query
使う場合、どうなるでしょう。
React Queryサンプル
React Query
を利用するためにはreact-queryパッケージをインストールする必要があります。
yarn add react-query
or
npm install react-query
先のフックをReact Query
使って書き直します。
import { useQuery } from 'react-query';
...
function useListQuery() {
const {data, isLoading, isError} = useQuery("list", async () => {
const { data } = await axios.get("/api/list");
return data;
});
return {
data,
isLoading,
isError,
};
}
これだけで完了です、かなりシンプルになったと思います
React Query
ではコードにある通り、第一引数に任意の名前のユニークキー
、第二引数にはpromiseを戻す関数
を設定します。
const result = useQuery('ユニークキー', Promiseを返す関数)
React Query
のキャッシュ機能はこのユニークキーによって実現している、一度取得したデータはしばらキャッシュされて、キーが変わるタイミングで、データを再度取得します。
ユニークキーは文字列以外、リストやオブジェクトにすることもできます。
useQuery('list', ...)
useQuery(['list'], ...)
useQuery(['list', 1], ...)
userQuery(['list', {
page: 1
}])
useQuery({
type: 'list',
page: 1
})
それらを踏まえて、ユーザーごとのデータを取得する際に、ユニークキーの書き方は下記のコードのようになるのが適切です。
const { data } = useQuery(
['getuser', userID],
() => axios.get(`/api/getuser/${userID}`).then(res => res.data);
)
さらに、useQuery
の第三の引数に{ enabled: userID !== undefined }
を追加すれば、userID
渡さない限り、リクエストは送信しません。
const { data } = useQuery(
['getuser', userID],
() => axios.get(`/api/getuser/${userID}`).then(res => res.data),
{ enabled: userID !== undefined }
)
データを変更する場合useMutation
というフックがあります。
import { useMutation } from "react-query"
function App() {
const [isLoading, isError, mutate] = useMutation(() => axios.post("/api/list", { newList }));
async function onSubmit() {
await mutate()
}
if (isLoading) {
return <p>データ送信中...</p>;
}
if (isError) {
return <p>エラー...</p>;
}
return <button onClick={onSubmit}>submit</button>;
}
その他の使い方は公式ドキュメント参考にしてください。
キャッシュコントロール
staleTimeとcacheTime
React Query
は取得してきたデータを自動的にキャッシュする際に、条件を設定することができます。
- cacheTime: データをキャッシュする時間, デフォルトは5分。
- staleTime: キャッシュしたデータが古くなったとみなす時間,デフォルトは0。
例えばlistデータを取得し、その1分後再度listを取得し直す場合、すでにlistはキャッシュされているのでリクエストなしで表示可能です。
一方でstaleTimeが0のため、キャッシュを返した後にサーバーにリクエストを投げます。
データが新しくなっている場合はそちらの値に書き換えられます。
const { isLoading, isError, data } = useQuery(
"list",
async () => {
const { data } = await axios.get("/api/list");
return data;
},
{ staleTime: 0, cacheTime: 5 * 60 * 1000 }
)
リクエストの送信を最小限に抑えたい場合、staleTime
を Infinity
に設定することができます。
そうすれば、キャッシュは常に新鮮なものとみなされるのでバックグラウンドでのフェッチは自動的には行われません。
でも明らかデータ変更があった場合、最新のデータを表示したいときにuseQueryClient
を使うことができます。
useQueryClient
useMutation
使ってデータを変更した後に、React Query
にキャッシュされてる古いデータを更新したい場合、
useQueryClient
使って、手動でキャッシュの更新ができます。
仮に、useQueryを使って管理してるデータの中に、ユニックキーがlist
のものがあるとします、useMutationでそのデータに新たなデータを追加した際に、追加が成功すれば queryClient
にキーを指定してデータを更新できます。
import {useQueryClient} from 'react-query'
const listForm = (data) => {
...
const queryClient = useQueryClient()
const { mutate } = useMutation(
() => axios.post("/api/list", { newList }),
{ onSuccess: () => {
queryClient.invalidateQueries(["list"])
}
}
)
これで更新されたlistが表示されるようになると思います。
最後に
この記事はあくまでReact Query
使用する場合の雰囲気を伝わるもので、実際プロジェクトに導入する際に、ルートコンポネートにQueryClientProvider
を追加するところから始めると思います、詳細は公式ドキュメントをご参考ください。