作成日:2022-09-16 ・更新日:2023-11-28
React-queryで通信回数の抑制、画面レンダリングの抑制が簡単にできました。fetchで更新があった場合のみ画面の再レンダリングする。無駄にサーバに問い合わせさせない、画面をレンダリングさせないようにすることができます。
React Queryはstate管理ライブラリーらしい。
どういう場面で使用するかと言うとサーバに問い合わせるHTTP POST、GETの回数を減らしたい、キャッシュを使用して欲しい時に使用するものです。取得データはページ移行しても維持しているため無駄にサーバーに問い合わせをすることが無くなります。
サーバに問い合わせする必要がある場合はこのライブラリーは必須だと感じていましたが、React 18でsuspenseが使えるようになったので使わなくてもいい状況も出てきました。
個人的に良かったところ
まずはインストール
npm i @tanstack/react-query
react-queryには現在 react-queryと@tanstack/react-queryがあり。今は@tanstack/react-queryに統合されたよう。 また、@tanstackは「useQuery(['uid'])」と配列でkeyを指定する必要がある。
import logo from './logo.svg';
import './App.css';
import {
useQuery,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
const queryClient = new QueryClient()
function App() {
return (
<div className="App">
<QueryClientProvider client={queryClient}>
<Component1/>
</QueryClientProvider>
</div>
);
}
export default App;
const Component1 = (()=>{
const query = useQuery(['uid'], Getcfetch)
if(query.isLoading)return(<div>isLoding.....</div>)
return (<div>
<p>aaaaaaaaa</p>
<p>{query.data.msg}</p>
</div>)
})
//fetchgeturlは各自用意する必要があります。
const Getcfetch = (async()=>{
const fetchgeturl = "http://demo8905806.mockable.io/decs";
const products = await fetch(fetchgeturl, {
method: "GET",
})
.then(datas => datas.json())
console.log(products);
return products
})
GETでHellow worldが表示されれば成功です。
React Queryの使うには以下の3つを用意する必要がある
クライアントを作成します。一番上の親に一度宣言するだけで大丈夫です。
QueryClientProviderにクライアントを指定し、囲みます。 プロバイダーが無くてもできるのでは?と色々見て試してみましたがどうやら必要らしいです。
useQueryにユニークキーとfetchファンクション + optionsを与えることで。 ファンクションが実行されその戻り値が保持されます。
公式ページでかなり多くのオプションが用意されていますが、以下9個のオプションだけでほとんど状況に対応できると思います。
const SuccessEvent = ((data) =>{
console.log(data);
});
const ErrorEvent = ((data) =>{
console.log(data);
})
const SettledEvent = ((data) =>{
console.log(data);
})
const navigate = useNavigate();
const query = useQuery(['uid'], Getcfetch , {
refetchInterval: 100000,
cacheTime: 600000,//60 * 10000 * 10,
staleTime: Infinity,
notifyOnChangeProps: ["data"],
onSuccess : (data) => SuccessEvent(data) ,
onError : (data) => ErrorEvent(data) ,
onSettled : (data) => SettledEvent(data) ,
refetchOnWindowFocus : false ,
enabled : true
})
refetchIntervalを利用すると指定した間隔で再度ファンクションを実行します。 1000 = 1秒になっています。
cacheTimeとstaleTimeを利用します。
fetchで値を取得しましたが、デフォルトの設定では取得ごとにfetchの時間等、取得データ以外も変わるため画面レンダリングが実行されてしまいます。取得できた情報が異なる場合のみ画面に反映させたいのでnotifyOnChangeProps: ["data"]を設定します。 つまり取得「"data"」が異なった場合のみと指定しています。 この設定をすることによってfetch後の取得データが同じだった場合レンダリングが行われません。
fetch「成功時,失敗時、最後に」の3つの状態でファンクションを実行することができます。 try catch finallyと同じでね。
enabled : trueとかなり簡単で普通のオプションですが、 上記の「データの取得成功時」のみファンクションを実行するような使い方で、特定のユーザー、ログイン状態、特定の処理後など、条件によってfetchを実行させるかどうか柔軟に対応できます。
親からデータを取り出したい場合はuseQueryを使用すると普通にデータの中身を取得できます。 あまり使う事はないとは思いますが...
//親で宣言したところに
const queryClient = new QueryClient()
<QueryClientProvider client={queryClient}>
//...省略
const data = queryClient.getQueryData()
デバック用の確認画面も用意されています。 公式ページ 導入もとても簡単です。
npm i @tanstack/react-query-devtools
後はインポートをしてプロバイダー内に記入してするだけです。
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
//...省略
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
react-router-domを使う場合でも特に問題ありません。
import logo from './logo.svg';
import './App.css';
import {
useQuery,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { BrowserRouter , Routes, Route,useNavigate } from "react-router-dom";
function App() {
const queryClient = new QueryClient()
const getcatch = (()=>{
const data = queryClient.getQueryData()
console.log(data);
})
return (
<div className="App">
<QueryClientProvider client={queryClient}>
<button onClick={getcatch}>getdata</button>
<BrowserRouter>
<Routes>
<Route path="/" element={<Component1/>}/>
<Route path="/b" element={<Component2/>}/>
</Routes>
</BrowserRouter>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</div>
);
}
export default App;
const Component1 = (()=>{
const navigate = useNavigate();
const query = useQuery(['uid'], Getcfetch , {
refetchInterval: 100000,
cacheTime: 600000,//60 * 10000 * 10,
staleTime: Infinity,
notifyOnChangeProps: ["data"],
})
if(query.isLoading)return(<div>isLoding.....</div>)
return (<div>
<p>aaaaaaaaa</p>
<button onClick={(()=>(navigate('/b')))}>routeB</button>
<p>{query.data.msg}</p>
</div>)
})
const Component2 = (()=>{
const navigate = useNavigate();
const query = useQuery(['uuid'], Getcfetch ,{
refetchInterval: 100000,
cacheTime: 600000,//60 * 10000 * 10,
staleTime: Infinity,
notifyOnChangeProps: ["data"],
} )
if(query.isLoading)return(<div>isLoding.....</div>)
return (<div>
<p>bbbbbbbbbb</p>
<button onClick={(()=>(navigate('/')))}>routeHome</button>
<p>{query.data.msg}</p>
</div>)
})
const Getcfetch = (async()=>{
const fetchgeturl = "http://demo8905806.mockable.io/decs";
const products = await fetch(fetchgeturl, {
method: "GET",
})
.then(datas => datas.json())
console.log(products);
return products
})
上記のコードで「useNavigate」を使ってページ移行してもfechをしないことが確認できました。 また、キャッシュが存在しない場合。古い場合そしてインターバル時間によってはfechを実行しています。
プロバイダーっで必要ですか?と思いましたが必ず必要でした。 react-router-domを使用している場合ページ移行は必ずuseNavigateを使う必要があります。
キャッシュが存在する場合でもfetchが走ってしまいサーバに問い合わせをしてしまいます。
そのためstaleTimeが存在しています。
キャッシュが存在していて、尚且つstaleTimeの時間内(最新のデータ)だと判断された場合は何もせずキャッシュのデータを使用します。
ページ移行にはaタグを使用せずにnavigateを使用しましょう。
post時にデータを渡す事があると思います。useQueryにそのまま引数を渡すと処理はしてくれるのですが、取得データが無いと言われてしまいます。その場合は即時関数を使用してください。
// const { data, isLoading } = useQuery(['Event'],getsql(props))<-- undefined
const { data, isLoading } = useQuery(['Event'], () => getsql(props))
正直まだまだ使いこなせていません。next.jsの場合はクライアントをstateにすると正常動作したり、いまだに謎です。
react-querは確かにGET POST時に使用すると,とても便利です。必須だとも感じます。デバックモードもかなり完成度が高くて助かっています。さらにreduxまたはrecoilを使用してより分かりやすくstateを使用しなければならないのですが...どのようにするのが正解なのか...
質問や、間違いがありましたら、お気軽にどうぞ
※お名前とコメントの内容を入力してください。
※全てこのブログ上に公表されます。
※許可なく管理者によって修正・削除する場合がございます。 詳しくはプライバシーポリシーを参照ください