ללא קשר כרגע לReact Query, כל נושא אימות המשתמשים באתרים יכול להיות קשה להבנה. יש תהליך שקורה בצד שרת ויש תהליך שקורה בקליינט, יש טוקן, קאש וכו…
אני לא הולך להיכנס לבסיס של אימות משתמשים, הרי זהו פוסט שנרשם מתוך מקום של הבנה מוקדמת של אימות משתמשים… אבל, מתוך פוסט זה, אני מאמין שאפילו אם אתם לא מכירים לעומק נושא של אימות, זה רק יעזור לכם להבין את הנושא אפילו טוב יותר. אז בואו נתחיל עם ציור פשוט שיסביר מה קורה פה בתהליך, ואיפה React Query בא לעזר.
אז לאחר שמשתמש מבצע התחברות, נוצר טוקן שנשמר בדטה בייס, ומאפשר לנו לבדוק באופן "אוטומטי" אם הטוקן עדיין ולידי, ולהציג את נתוני המשתמש ללא צורך בהתחברות.
מי ישמור לנו את הטוקן, בצד לקוח הוא חברינו החדש React Query, ונדאג לטפל בו בבטחה במצבים בהם פג הטוקן או התנתקות ואפילו עדכון של נתוני המשתמש, וכל זה בשביל לייצר חווית קליינט אולטימטיבית. כעת נסתכל על מימוש פשוט של authentication עם React Query:
async function getUser(userId: number, userToken: string) { const { data }: AxiosResponse<{ user: User }> = await axiosInstance.get( `/user/${userId}`, { headers: getJWTHeader(userToken), } ); return data.user; } const { data: user } = useQuery({ enabled: !!userId, queryKey: ["user", {userId, userToken}], queryFn: () => getUser(userId, userToken), staleTime: Infinity, });
זו הפונקציה שעושה שימוש בקאש של query client אחר שהמשתמש מחבר פעם אחת. enabled מאפשר לנו לשים בדיקה של true/false , במידה של false , הפונקציה לא תפעל שוב. staleTime הוגדר להיות Infinity כך שהדטה לעלום לא יחשב כישן, כלומר, רק לאחר ש gcTime (ברירת מחדל 5 דק) יפוג והקאש יתנקה. ואז בטעינה הבאה תתבצע בקשה חדשה לשרת.
עדכון ומחיקת נתונים עם React Query Authentication
אז למעשה לאחר ההתחברות, אנחנו נשמור נתונים בקאש. נתונים אלו זמינים לנו, ונוכל לבצע GET של דטה עבור המשתמש שאיתו התחברנו (כפי שראינו בקוד לעיל). אז מה קורה במצב של עדכון נתונים? כיצד זה מתבצע? ואיך React Query עוזר לנו?
עדכון נתונים של המשתמש
אז לעדכון נתונים נוכל להשתמש ב useMutation של React Query. ולשם כך נכין את ה hook הבא:
export const MUTATION_KEY = "patch-user"; // for when we need a server function async function patchUserOnServer( newData: User | null, originalData: User | null ): Promise<User | null> { if (!newData || !originalData) return null; const patch = jsonpatch.compare(originalData, newData); const { data } = await axiosInstance.patch( `/user/${originalData.id}`, { patch }, { headers: getJWTHeader(originalData.token), } ); return data.user; } export function usePatchUser() { const { user } = useUser(); const queryClient = useQueryClient(); const { mutate: patchUser } = useMutation({ mutationKey: [MUTATION_KEY], mutationFn: (newData: User) => patchUserOnServer(newData, user), onSuccess: () => { toast({ title: "User updated!", status: "success" }); }, onSettled: () => { return queryClient.invalidateQueries({ queryKey: ["user"], }); }, }); return patchUser; }
בעזרת usePatchUser אנחנו עושים שימוש בuseMutation, שעושה שימוש ב onSettled, שהוא מעיין sideEffect, שמתבצע לאחר Mutation, ואז עושה invalidateQueries, שלמעשה מעדכן את המידע לקאש ששמור על queryKey שקשור לkey : בשם user.
וכך למעשה אנחנו מקבלים עדכון של המידע שנשמר בqueryClient בקוד שמוצג ב useUser שעושה שימוש בuseQuery.
מחיקת נתונים של המשתמש
בשביל למחוק את נתוני המשתמש, נצטרך למצוא את המצבים בהם נרצה בכך, למשל logout:
function clearUser() { queryClient.removeQueries({ queryKey: ["user"] }); }
פונקציה נוספת שנרשום בתוך useUser היא clearUser, שתעשה שימוש בqueryClient ולמעשה תנקה את כל הקאש ששמור על queryKey שהוא "user".
בהמשך הקוד יש שימוש גם בcontext שמתעדכן גם כן, ולמעשה גם עושה מחיקה גם מה context ואז דואג לידע את הקליינט ולבצע redirect מתאים.
לסיכום React Query and Authentication
הצגנו את יסודות אימות המשתמשים ב client side בשימוש עם React Query, לא הצגנו את כל השימושים, ישנם שימושים נוספים, ואף מאובטחים יותר, כמו כן , ניתן לעשות שימוש בlocal storage ובכך לשמור על תוקף התחברות ממושך… וכן שימושים נוספים לשיפור תצוגת הקליינט עם useMutationState… בכל מקרה, בפוסט הזה יש לכם בסיס טוב להמשיך ולפתח ולהכיר שימושים נוספים לאימות משתמשים בקליינט עם React Query.
בהצלחה בהמשך , נתראה בפוסט הבא 😻