React Query היא ספרייה פופולרית מאוד עבור ניהול נתונים ביישומים מבוססי React. היא מספקת לנו דרך יעילה ופשוטה לטפל בבקשות נתונים אסינכרוניות, כגון קריאות ל-API, והיא מטפלת באופן אוטומטי במגוון רחב של מצבים, כמו טעינה, הצלחה, כשלון, עדכון נתונים, ועוד…
בשביל להשתמש בreact-query, יש להתקין את הספרייה בפרויקט ריקאט, ישנה גרסה V3 וגרסה V4:
V4
npm i @tanstack/react-query
V3
npm i react-query
React Query וניהול מידע בסגנון server state
ניהול מידע בclient state למשל context הוא דבר מוכר וידוע. אך server state הוא מושג קצת יותר "חדש" או יותר מדויק וייחודי לשימוש בספריות כמו React Query. הרעיון הכללי הוא פשוט, לשמור מידע שמגיע מבקשות השרת ב cache על key ייחודי
להלן דוגמה:

React Query יודע לנצל את הקאש בצורה טובה מאד. ניתן לראות ולעקוב אחר הקריאות וכן לקבל מידע חיוני עבור ניהול המידע שעושה React Query עם Query Client Devtools , שזהו תוספת נפרדת מתוך סט הכלים של @tanstack/react-query
npm i @tanstack/react-query-devtools

את הkey רואים בצד שמאל – ["todos"] , בצד ימין אפשר כמובן לראות את הדטה שנשמר על אותו ה key, אקשנים (actions) שאפשר להריץ על הבקשה הספציפית, ועוד נתונים חשובים שנראה בהמשך הפוסט
React Query – איך מתחילים?
אז נקים פרויקט ריאקט (npm create vite) לצורך הדגמה שתלווה את ההסברים. כמו כן התקנתי את V4 של react-query וכמובן את react-query-devtools. חשוב לציין שreact-query-devtools לא מותקן בdev dependencies אבל לא יוצג בפרודקשן, מקוון שהוא נכלל רק כאשר process.env.NODE_ENV === 'development'. מי כן רוצה להציג את devtools בפרודקשן, יכול לקרוא באתר שלהם כאן.
להלן ההשמה של React Query עם QueryClientProvider , שנדרש לעטוף את האפליקציה שלכם במיקום ראשי. למשל בדוגמה פה , עטפנו את כל הרכיבים כבר בApp. כמו כן ניתן לראות שמיקמתי את ReactQueryDevtools בתוך QueryClientProvider .
import { useState } from "react"; import reactLogo from "./assets/react.svg"; import viteLogo from "/vite.svg"; import "./App.css"; import { queryClient } from "./hooks/queryClient"; import { QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { Todo } from "./Todo"; function App() { return ( <QueryClientProvider client={queryClient}> <Todo /> <ReactQueryDevtools /> </QueryClientProvider> ); } export default App;
עשיתי שימוש בqueryClient בקובץ נפרד לשם הנוחות, להלן הקובץ:
import { QueryClient } from "@tanstack/react-query"; export const queryClient = new QueryClient();
זה כל מה שצריך בשביל לממש את React Query.
שימוש בuseQuery
הכירו את useQuery, הפונקציה הבסיסית והשימושית ביותר שיש לreact-query להציע, נעבור על חלק מהשימושים שניתן לעשות עם useQuery, אך קודם אציג דוגמה מתוך הקוד:
import { QueryKey, useQuery } from "@tanstack/react-query"; export const useFetch = <T,>(api: string, keys: QueryKey) => { const { data } = useQuery({ queryKey: keys, queryFn: async () => { const res = await fetch(api); return res.json(); }, }); return data as T; };
import { useFetch } from "./hooks/useFetch"; type TodoType = { userId: number; id: number; title: string; completed: boolean; }; export const Todo = () => { const data = useFetch<TodoType[]>( "https://jsonplaceholder.typicode.com/todos", ["todos"] ); if (!data) { return <div>Loading...</div>; } return ( <div> {data?.map((todo) => ( <div style={{ textAlign: "start", padding: "10px 30px", margin: 20, background: "white", boxShadow: "0 0 20px rgba(0,0,0,0.1)", }} key={todo.id} > <h2>{todo.title}</h2> {todo.completed ? ( <p style={{ color: "#00FF00", fontStyle: "italic", }} > Completed </p> ) : ( <p style={{ color: "#FF0000", fontStyle: "italic", }} > Not Completed </p> )} </div> ))} </div> ); };
כמו כן שימושים רבים עם useQuery . להלן כל האפשרויות של פונקציה זו
const { data, dataUpdatedAt, error, errorUpdateCount, errorUpdatedAt, failureCount, failureReason, fetchStatus, isError, isFetched, isFetchedAfterMount, isFetching, isInitialLoading, isLoading, isLoadingError, isPaused, isPlaceholderData, isPreviousData, isRefetchError, isRefetching, isStale, isSuccess, refetch, remove, status, } = useQuery({ queryKey, queryFn, cacheTime, enabled, networkMode, initialData, initialDataUpdatedAt, keepPreviousData, meta, notifyOnChangeProps, onError, onSettled, onSuccess, placeholderData, queryKeyHashFn, refetchInterval, refetchIntervalInBackground, refetchOnMount, refetchOnReconnect, refetchOnWindowFocus, retry, retryOnMount, retryDelay, select, staleTime, structuralSharing, suspense, useErrorBoundary, })
ערכי השיבה של useQuery:
- data: הנתונים שהתקבלו מהבקשה.
- dataUpdatedAt: זמן העדכון האחרון של הנתונים.
- error: שגיאה שהתרחשה במהלך הבקשה.
- errorUpdateCount: מספר הפעמים שהשגיאה עודכנה.
- errorUpdatedAt: זמן העדכון האחרון של השגיאה.
- failureCount: מספר הכשלונות של הבקשה.
- failureReason: הסיבה לכשלון האחרון.
- fetchStatus: מצב הטעינה הנוכחי (idle, fetching, success, error).
- isError: האם התרחשה שגיאה.
- isFetched: האם הנתונים נקראו בהצלחה לפחות פעם אחת.
- isFetchedAfterMount: האם הנתונים נקראו בהצלחה לאחר הרכבת הרכיב.
- isFetching: האם הבקשה מתבצעת כרגע.
- isInitialLoading: האם הבקשה הראשונית מתבצעת.
- isLoading: האם הנתונים עדיין נטענים.
- isLoadingError: האם התרחשה שגיאה במהלך הטעינה הראשונית.
- isPaused: האם הבקשה מושהית.
- isPlaceholderData: האם מוצגים נתוני פלייסהולדר.
- isPreviousData: האם מוצגים נתונים קודמים.
- isRefetchError: האם התרחשה שגיאה במהלך רענון.
- isRefetching: האם מתבצע רענון של הנתונים.
- isStale: האם הנתונים מיושנים.
- isSuccess: האם הבקשה הצליחה.
- refetch: פונקציה לרענון הנתונים באופן ידני.
- remove: פונקציה להסרת הבקשה מהמטמון.
- status: מצב הבקשה (idle, loading, success, error).
ערכי הקונפיגורציה של useQuery:
- queryKey: מפתח ייחודי לבקשה.
- queryFn: פונקציה שמבצעת את הבקשה.
- cacheTime: זמן החיים של הנתונים במטמון. ערך דיפולטיבי 5 דקות
- enabled: האם להפעיל את הבקשה.
- networkMode: מצב הרשת (online, offline).
- initialData: נתונים התחלתיים.
- initialDataUpdatedAt: זמן עדכון הנתונים ההתחלתיים.
- keepPreviousData: האם לשמור נתונים קודמים.
- meta: מטה-נתונים לבקשה.
- notifyOnChangeProps: מערך של שמות נכסים לעדכון כאשר הם משתנים.
- onError: פונקציה להפעלה במקרה של שגיאה.
- onSettled: פונקציה להפעלה בסיום הבקשה (הצלחה או כשלון).
- onSuccess: פונקציה להפעלה במקרה של הצלחה.
- placeholderData: נתוני פלייסהולדר.
- queryKeyHashFn: פונקציה לחישוב ערך hash למפתח הבקשה.
- refetchInterval: מרווח זמן לרענון אוטומטי.
- refetchIntervalInBackground: האם לבצע רענון אוטומטי ברקע.
- refetchOnMount: האם לרענן את הנתונים בעת הרכבת הרכיב.
- refetchOnReconnect: האם לרענן את הנתונים בעת חיבור מחדש לרשת.
- refetchOnWindowFocus: האם לרענן את הנתונים בעת פוקוס על החלון.
- retry: מספר ניסיונות חוזרים במקרה של שגיאה.
- retryOnMount: האם לנסות שוב בעת הרכבת הרכיב.
- retryDelay: עיכוב לפני ניסיון חוזר.
- select: פונקציה לבחירת נתונים מהתוצאה.
- staleTime: זמן פיגור לפני שהנתונים נחשבים מיושנים. ערך דיפולטיבי – 0
- structuralSharing: האם להשתמש בשיתוף מבני עבור הנתונים.
- suspense: האם להשתמש ב-Suspense.
- useErrorBoundary: האם להשתמש ב-ErrorBoundary.
לסיכום – React Query – useQuery
לסיכום, React Query מספקת פתרון מקיף ויעיל לניהול נתונים ביישומי React, ומאפשרת למפתחים לבנות יישומים מהירים, אמינים וניתנים לתחזוקה.
האם תרצה ללמוד על נושא ספציפי נוסף הקשור ל-React Query? בפוסטים הבאים:
- Mutations: כיצד לשנות נתונים בשרת
- Pagination: כיצד לטעון נתונים בדפים
- Infinite Loading: כיצד לטעון נתונים נוספים בעת גלילה