نگاهی به Server State و React-Query در React

داستان از جایی شروع شد که برای مدیریت و ساخت Redux اپلیکیشن دنبال best practice ای بودم، که بتونم با اون دیتای گرفته شده از API ها و اطلاعات ورودی‌ کاربر به اپلیکیشن رو، به خوبی داخل Redux مدیریت کنم. پس مثل همیشه دست به سرچ شدم تا best practice ایده‌آل رو پیدا کنم.متاسفانه یا خوشبختانه روش ایده‌آلی برای پیدا سازی APIها داخل ریداکس نیست؛ اما طبق داکیومنت برای best practice گفته شده از redux-toolkit استفاده بشه. بعد از کلی گشتن، به روش جدید و جالبی برای مدیرت State های اپلیکشن برخوردم؛ توی این روش دیگه خبری از مدیریت کردن دیتای گرفته شده از API ها داخل Redux نیست. توی این روش State های ما به دو بخش تقسیم میشه: Client State و Server State .Client State دیتای global ای هست که از کاربر گرفته میشه، مثل theme, language و غیره. Server State دیتایی هست که به واسطه API کال‌ها وارد اپلیکیشن میشه.مثل Redux که ابزاری برای مدیریت Global State هست، برای مدیریت Server state هم به ابزار خاص خودش نیاز داریم که از معروف‌ترین این ابزارها میشه به React-Query و SWR اشاره کرد. توی این مقاله به چگونگی اضافه کردن React-query و ویژگی‌های مهم اون در اپلیکیشن React میپردازیم.ویژگی Server State Manager ها مهم‌ترین ویژگی‌ای که این ابزارها به پروژه‌های React‌ای میدن: حذف کدهای تکراری (boilerplate) برای مدیریت کردن هر ریکوست، resolve و reject شدن اونها توی reducer هست. در کنار این مزایا، ویژگی‌های جذاب دیگه‌ای هم مثل:کشینگ سیستم خودکار (Caching System)بررسی کردن و بروز کردن دیتاها در صورت پیدا کردن دیتای جدیدتر مدیریت کردن فرآیند API کال ( error, data, loading و غیره) مدیریت memory و garbage collectionویژگی های این ابزار فقط به موارد بالا خلاصه نمیشه. علاوه بر این، دارای هوک‌های (hook) پیش ساخته مثل برای infinite scroll , pagination و کلی هوک های دیگه برای شرایط خاص‌تر داره. دیگه مقدمه چینی کافیه بریم دست به کد بشیم.نصب و راه اندازی React-Query ترمینال خودتون رو باز کنید و package رو با استفاده از کدهای زیر نصب کنید:npm i react-query or yarn add react-queryبعد از نصب package نیاز به ساخت QueryCilent و QueryClientProvider هست.import { QueryClient, QueryClientProvider } from 'react-query' // Create a client const queryClient = new QueryClient() function App() { return ( // Provide the client to your App <QueryClientProvider client={queryClient}> <App/> </QueryClientProvider> ) }برای اینکه بتونیم از React-query توی تمام اپلیکیشن استفاده کنیم نیاز هست داخل فایل app.js کد بالا رو وارد کنیم. با استفاده از فانکشن QueryClient یک نمونه client provider جدید برای ما ساخته میشه و با احاطه کردن (wrap) کامپوننت QueryClinetProivder دور کامپوننت App ، Server State Mangement خودمون رو می سازیم.اضافه کردن devtoolsبرای دیدن دیتای ذخیره شده و مابقی اطلاعات می تونیم از devtools استفاده کنیم، فقط کافیه کد زیر به عنوان فرزند به کامپوننت QueryClientProvider اضافه بشه:import { ReactQueryDevtools } from 'react-query/devtools' function App() { return ( <QueryClientProvider client={queryClient}> <App/> <ReactQueryDevtools /> </QueryClientProvider> ) }پس از اضافه کردن devtools لوگو react-query به صورت پیش فرض پایین سمت چپ مرورگر شما ظاهر میشه و با کلیک بر روی لوگو devtools باز میشه.نمای کلی محیط devtoolsکاربرد useQuery hook هوک useQuery برای گرفتن اطلاعات (GET) و ذخیره‌ی دیتا به واسطه یک uniqueQueryKey منحصر به فرد داخل caching system هست. یا به زبان ساده، دیتا تحت یک اسم خاصی در caching system ذخیره میشه. این هوک، سه پارامتر دریافت میکنه:پارامتر اول (اجباری): این پارامتر هم رشته دریافت میکنه و هم آرایه.پارامتر دوم (اجباری): فانکشنی دریافت میکنه که مقدار خروجی آن یک promise هست.پارامتر سوم (اختیاری): ابجکتی دریافت میکنه که می تونه تنظیمات هوک تغییر بده. import { useQuery } from 'react-query'; const fetcher = () => fetch(url).then(res => res.json()) function Component() { const { data, error, isLoading , ...rest } = useQuery('posts', fetcher , options) return ( // jsx ) }به طور کلی توی کد بالا هوک useQuery یه uniqueQueryKey به نام posts قرار دادیم، که نتیجه فانکشن fetcher که یک promise هست رو داخل اون قرار بده. options هم یک پارامتر اختیاری هست که برای تغییرات تنظیمات پیشفرض میشه از اون استفاده کرد.در اخر هم میتونیم با object destructuring اطلاعات خروجی مورد نظرمون از useQuery رو گرفته و استفاده کنیم.تنظیمات پیشفرض مهم React-Queryبه عنوان مثال، هوک‌های useQuery و useInfiniteQuery رو بعد از گرفتن دیتا، ذخیره و cache کردن در اپلیکیشن به عنوان دیتای قدیمی یا تاریخ گذشته ثبت میکنه. یا به اصطلاح stale شده و وقتی به این شکل باشه، react-query تلاش می کنه تا در اولین فرصت دیتا رو دوباره از اون API کال گرفته و مقایسه کنه؛ که آیا دیتا بروز شده یا نه. اگه دیتا تغییری نکرده باشه که از دیتای cache شده استفاده میکنه و در غیر اینصورت، اطلاعات جدید رو گرفته و جایگزین اطلاعات cache شده میکنه.و اما قسمت مهم اینه که، کی و در چه صورتی اطلاعات رو مجدداً می‌گیره:نمونه‌ جدیدی از کوئری mount بشه.روی پنجره مرورگر مجدداً focus بشه.کانکشن اینترنت دوباره برقرار بشه.و یا اینکه تایمری برای بررسی و گرفتن دیتاها تنظیم کرده باشیم.توی فاز دولوپ کردن حواستون به مورد شماره ۲ باشه، چون ممکنه زیاد اتفاق بیفته. react-query تنظیمات پیش‌فرض دیگه‌ای هم برای سیستم garbage collection داره که می تونید اینجا بیشتر بخونید.توی این مقاله تلاش کردم تا مفاهیم اولیه و یکی از هوک‌های مهم این پکیج رو معرفی کنم. اطلاعات بیشتر رو می تونید از داکیومنت اصلی بخونید. خالی از لطف نیست که به پکیج رقیبش swr، که vercel نوشته هم یه نگاهی بندازید.