با ریکت کوئری کنترل بیشتری روی داده های دریافتی از سمت سرور داریم، میتوان داده های مورد نظر رو از api گرفت و اون رو کش(cache) میکنه و...
در واقع منطق ریکت کوئری میگه ک شما یه تابع fetcher به من بده ( مثل fetch ,axios ,... اون چیزی که میخواد یه تابع یک دیتا برگردونه) بقیه عملیات مثل کش کردن و آپدیت کردن و... با من.
در واقع ریکت کوئری میاد چیکار میکنه؟ میاد اول دیتا ما رو میگیره از api و بعد با همون key ک تعریف کردیم، دیتا رو با همون key کش میکنه و بعد نشون کاربر میده( توجه داشته باشید که اگه دفعه بعدی همون useQuery یا هر تابعی از react query رو با همون key صدا زد -> بصورت موازی که داره دیتا کش شده همون key رو نشون کاربر میده، میره دیتا رو از سرور میگیره و اگه دیتا تغییری نکرد ک هیچ کاری نمیکنه. اما اگه دیتا گرفته شده مغایرت داشت با دیتا کش شده( حتی یه کلمه اش) میاد کل دیتا رو جایگزین دیتا کش شده میکنه و نشون کاربر میده.)
ببینید از مزایای ریکت کوئری میشه به این اشاره کرد ک دیگه شما state اضافه ای مثل loading,data,error و اینا تعریف نمیکنید. یعنی چی؟
یعنی اینکه شما وقتی بصورت عادی یه Api رو کال میکنید
call api=>
setState loading=true;
setState data=fetch from data;
setState error="message error";
نیاز دارید به حداقل این نمونه stateها ک با استفاده از ریکت کوئری دیگه نیازی به تعریف این قبیل stateها ندارید و خودش هندل میکنه و هر زمان خروجی رو به ما میده
توجه: توجه داشته باشید که ریکت کوئری رو باید توی خود کامپوننت تعریفش کنید! یعنی نمیتونید توی یه فانشن تعریفش کنید و... باید توی خود root کامپوننت تعریفش کنید.
خب برای استفاده از ریکت کوئری ابتدا باید در اولین پیجی ک برنامتون فراخوانی میشه حالا یا app یا index پروژه تون این کانفیگ رو بزارید
(البته توجه داشته باشید ک باید @tanstack/react-query رو نصب کنید )
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
const queryClient = new QueryClient();
وQueryClientProvider رو اول کدهای ک نوشتید بزارید
<QueryClientProvider client={queryClient}></QueryClientProvider>
بعنوان مثال من توی فایل index.js م اومدم اینطور گذاشتم
import React from 'react';
import {AppRegistry} from 'react-native';
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
import App from './app/App';
import {name as appName} from './app.json';
const queryClient = new QueryClient();
const MyProject= () => (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
AppRegistry.registerComponent(appName, () => MyProject);
خب حالا نمونه استفاده از useQuery رو اول میگم
توی جای ک میخواید استفاده کنید(منظورم کامپوننت یا صفحه و...)
اول importش میکنید
import { useQuery } from '@tanstack/react-query'
سپس
const { isLoading, isError, data, error } = useQuery({queryKey: ['todos'],queryFn: fetchTodoList,})
اینطور استفاده میکنیم، ک حالا به توضیح تک تکشون میپردازیم
فقط دقت داشته باشید ک
خروجی useQuery بیشتر از این 4 مورد هست ک از پایین میتونید بقیه موارد رو اضافه یا کم کنید،و همینطور ورودیش
ک در ابتدا وقتی تو صفحه میخواید لودش کنید اول isLoading مقدارش trueهست تا هر موقع دیتا گرفت این isLoading مقدارش فالس میشه
یعنی خود ریکت کوئری متناسب خروجی هرکدوم رو ست میکنه ک ما با این خروجیا میتونیم دیتا مورد نظرمون رو به کاربر بگیم
مثلا میتونیم بزاریم
isLaoding? (</Loading>):(data or error handel)
یعنی اگه loading مقدارش true بود میگیم به کاربر loading رو نشون بده اگه نه بره همینطور error یا data رو هندل کنه و متناسب باهاش داده مورد نظر رو به کاربر نشون بده
اما آرگومانهای ورودی:
queryKey
این مقدار برای هر useQuery که ما میسازیم باید uniqe باشه(یعنی خاص و غیر تکراری چون دیتا دریافتی از سرور با این key ذخیره میشه) و همینطور ک توی مثالش هم مشخصه باید رشته باشه
و آرگومان دوم
queryFn
همون تابع fetcherی ک از قبل ساختیم
و همینطور ما option های اضافه تری هم میتونیم داشته باشیم
مثلا ما نمیخوایم با لود صفحه useQuery ما صدا زده بشه میخوایم وقتی روی یه دکمه(یا باتن) بزنیم این useQuey فراخوانی بشه خب از enable=fale استفاده میکنیم
برای مثال من اینطور نوشتم
const {isLoading,isInitialLoading,isError,data,error,refetch,isFetching,} = useQuery({
queryKey: ['useInventoryList'],queryFn: () =>getInventoryList({RowFrom:0,RowCount:10}),
enabled: false,
});
ک هر موقع میخواید صداش بزنید باید refetch رو صدا بزنید
و همینطور میتونید تایم کش رو کم و زیاد کنید و آپشنهای زیاد دیگه ای ک خودتون بقیه داکیومنت رو بخونید و تست کنید
هدف من یه سمپل ساده از useQuery بود
اما یه هوک دیگه از ریکت کوئری useQueryClient
هست (البته یکی از کاربرداش ک من کار کردم میدونم اینه) که داریم یه useQuery رو مثلا با page=1 صداش میزنیم و توی بطن ماجرا هم میخوایم همزمان page=2 رو هم صدا بزنیم
بعنوان مثال
queryClient=useQueryClient();
queryClient.prefetchQuery(queryKey,queryFn)
در واقع میره دیتا page بعد رو هم میگیره و کش میکنه ک برای دفعات بعدی میخوایم page بعد رو صدا بزنیم سرعت لودش سریع باشه
اما هوک دیگه useInfiniteQuery
هست ، ما گاهی یک Api داریم ک علاوه بر page=1 باز به page قبل و بعدش نیاز داریم در واقع دیتا همراه با paggination بیاد ک از این هوک استفاده میکنیم ک در واقع دیتا قبل و بعدی رو هندل میکنه و چک میکنه ک آیا page بعدی دیتا داره یا نه و...
نمونه استفاده ازش
const {fetchNextPage,fetchPreviousPage,hasNextPage,hasPreviousPage,isFetchingNextPage,isFetchingPreviousPage,...result} = useInfiniteQuery({queryKey,queryFn: ({ pageParam = 1 }) => fetchPage(pageParam),...options,getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,})
که پارامترهای ورودی باز مشخصه و خروجی
اما یه توضیح لازم هست بدم درمورد
getNextPageParam
که دوتا ورودی داره این تابع و یک خروجی
ک ورودی اولش ک به اسم lastPage هست در واقع مقدار آخرین دیتا از آخرین pageی که ما به سرور ریکوست دادیم برای گرفتن دیتا api رو درون خودش نگه میدارد ( بنظرم بهتره اسمش رو به DataOfLastPage تغییر بدیم خوانایی و مفهوم رو بهتر میرسونه، این نظر شخصی منه! چون وقتی میگیم lastPage توی ذهن ما یه عدد تداعی میشه تا یه دیتا)
ورودی دوم allPage که داخلش همه دیتاهای همه pageهای ک تا حالا ریکوست داده به سرور رو داره(یعنی همه pageهای تا حالا دیتا گرفته رو داخش داره)
page =1 -> data1
page=2 -> data2
page=3 -> data3
که اگه بخوایم این مثال رو برای سه درخواست به سرور درنظر بگیرم مقدار lastPage ما شامل data3 میشه و مقدار allPage ما میشه هر سه مقدار data1, data2,data3
و همینطور خروجی getNextPageParam یک عدد هست ( در واقع یک شماره page رو ریترن میکنه) ک اون عدد میشه page بعدی ک باید queryFn فراخوانی کنه رو برمیگردونه ک این مقدار رو ما باید ست کنیم و توی ریترنش برگردونیم
توجه : مقدار pageParam
از تابع queryFn: ({ pageParam = 1 }) => fetchPage(pageParam)
ک در بار اول مقدارش رو میتونیم با 1 ست کنیم و برای بارهای بعد pageParam مقدار جدیدش رو از تابع getNaxtPageParam میگیره( که آخرین pageی ک باید فراخوانی بشه رو برمیگردونه)