סוף סוף סיימנו עם הצד שרת עד כה, ומי שעוד לא עקב על כל השיעורים האחרונים בקורס חינם זה מוזמן להציץ בהם כאן. לסיכום מה שעשינו זה צד שרת ב nodejs עם הרבה gql , הגדרנו schema עם mutation וquery.
קורס חינם React & GraphQL – שיעור ראשון – אתחול צד לקוח
קורס חינם React & GraphQL – שיעור שני – משחק איקס עיגול TIK-TAK-TOE
קורס חינם React & GraphQL – שיעור שלישי – צד שרת Nodejs של המשחק איקס עיגול.
קורס חינם React & GraphQL – שיעור רביעי – graphQL מגדירים schema.
קורס חינם React & GraphQL – שיעור חמישי – graphQL מגדירים schema.
קורס חינם React & GraphQL – שיעור שישי – graphQL על query and mutation. המשך.
חוזרים לצד לקוח עם Apollo Client
חזורים לאפליקציה הריאקטית שלנו וקודם כל נתקין 2 ספריות שיעזרו לנו לעבוד עם gql ב react :
- npm i @apollo/client – ספרייה זו מאוד פופולארית בעבודה עם react וgql מביאה איתה hooks build-in שעושים לנו חיים קלים.
- npm i graphql – כמובן נתקין גם את הספריה של GQL כי אחרת אפולו לא יעבוד לנו.
עוטפים את האפליקציה עם ApolloProvider
הדבר הראשון שצריך לעשות באפליקציה שלנו זה לייבא את ApolloProvider ולהגדיר את הprop של client כך למעשה כל האפליקציה (או חלק מסויים שבחרתם לעטוף – במקרה שלנו את כל האפליקציה) תוכל לבצע קריאות GQL.
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {ApolloClient, ApolloProvider , InMemoryCache} from '@apollo/client'; const client = new ApolloClient({ uri: "http://localhost:5001/graphql", cache: new InMemoryCache() }) ReactDOM.render( <React.StrictMode> <ApolloProvider client={client}> <App /> </ApolloProvider> </React.StrictMode>, document.getElementById('root') ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
זוהי קונפיגורציה בסיסית של GQL עם apollo client כל מה שאנחנו עושים פה זה מגדירים את client עם הURI שלנו כמו בשורה 9. שורה 10 הוספתי את InMemoryCache. חייבים להגדיר cache במקרה הזה לא הגדרתי כלום בתוך InMemoryCache ולכן ניהול הקאש התנהג בצורה דיפולטיבית של GQL. חשוב לציין שנושא הקאשינג עם GQL הוא מאד מעניין ונרחב, הצוות של GQL השקיעו לא מעט בכל נושא טיפול הקאשינג. בקורס GQL שהינו בסיסי לא נכנס לנושא הקאשינג , יש מצב שאני אעשה על זה כמה פוסטים בנפרד לקורס בהמשך .
וזהו כל שנשאר לנו זה לעטוף את האפליקציה האו רחיבי האפליקציה שיעשו שימוש בGQL.
שימוש בquery עם Apollo client
המידע שנרצה להציג הוא רשימת תוצאות המשחקים, כלומר אחרי שהמשחק יסתיים, נראה טבלה של המשחקים שהיו בין 2 השחקנים ששיחקו ומה תוצאותיהם , לשם כך , נצטרך לעשות קריאת query שכבר בנינו עוד בשיעורים האחרונים. אבל קודם נצטרך לבנות את הקריאות הללו בצד הלקוח:
import React, { useState, useEffect } from 'react' import { useQuery, gql } from '@apollo/client'; const GET_ALL_GAMES = gql` query results{ getResults { id player results } } ` const Results = (props: any): JSX.Element => { const { loading, data, error, refetch } = useQuery(GET_ALL_GAMES); const [gameResults, setResults] = useState<(any | null)[]>([]); useEffect(() => { if (data) { setResults(data.getResults); } }, [data]); if (loading) return <>'...'</>; return ( <div> <table> <thead> <tr> <th>Player Won</th> <th>Board Results</th> </tr> </thead> <tbody> {gameResults && gameResults.length > 0 && gameResults.map((game) => <tr key={game.id}> <td>{game.player}</td> <td>{game.results}</td> </tr>)} </tbody> </table> </div> ) } export default Results;
אז יש לנו פה את רכיב ה results קומפוננטה זו תעשה את כל העבודה עם הדטה שלנו. כמו כן נתחיל עם query.
שימו לב לשורה5-11 . זו אותה הקריאה שאנחנו בדקנו בסביבת הבדיקות בשיעורים הקודמים. כל מה שהיינו צריכים בשביל להשתמש בה בצד הלקוח זה לייבא את gql מתוך apollo client ולשים אותה בתוך backticks . לרוב תראו ששאילתות ירשמו באותיות גדולות עם מקו תחתון, אבל זה לשיקולכם. כמו כן יש הרבה מקרים ששאילתות ממוחזרות אז יהיה נוח להפריד אותן לקבצים נפרדים ולייבא אותן בעת הצורך.
הדבר הבא החשוב הוא useQuery (שורה 16) שמשמש כ hook שמחזיר את data, loading , error כך שנוכל לוודא שאין שגיאות ולתת חיווי מתאים או במצב של טעינה של הדטה (נוכל לשים איזה ספינר מתאים או כל דבר באחר שתבחרו) במקרה שלני עשיתי שימוש ב loading בשורה 26.
אני גם עושה שימוש ב useEffect ושומר את הדטה כשהוא מגיע לתוך הסטייס שהגדרתי בשורה17.
ואז שימוש פשוט בתוך הTSX שלנו. וזהו ויש לנו טבלה של תוצאות המשחקים .
אבל כרגע זה רק מציג תוצאות. וכל מה שיש שלנו זה קובץ mock עם תוצאה אחת. ולכן נעבור לשלב הבא ונבנה את mutation שישמור לנו את המידע בטבלה ואז נוכל לראות תוצאות של המשחקים שלנו.
שימוש ב mutation עם Apollo client
והנה החלק האומנתי שיציג לנו סוף סוף את מה שחיכינו לו כל הזמן הזה וזה טבלה של המחשקים שלנו. וכל זה בשימוש פשוט ונוח שמספק לנו apollo client . גם שימוש של mutation הוא בעזרת hook מובנה בשם useMutation והכל מאד דומה למה שעשינו עם query. להלן כל הקוד של results . יש פה הרבה דברים אז נעבור על זה שלב שלב..
import React, { useState, useEffect } from 'react' // import { results } from '../mock/results'; import { useQuery, useMutation, gql } from '@apollo/client'; const GET_ALL_GAMES = gql` query results{ getResults { id player results } } ` const ADD_GAME_RESULTS = gql` mutation CreateGameResults($id: Int, $player: String, $results: String){ createGameResults(id : $id, player : $player,results: $results){ player results } } ` const Results = (props: any): JSX.Element => { const { loading, data, error, refetch } = useQuery(GET_ALL_GAMES); const [gameResults, setResults] = useState<(any | null)[]>([]); const [newData, setNewData] = useState<(any | null)[]>([]); const [createGameResults,{data: dataMutation, error:errorMut}] = useMutation(ADD_GAME_RESULTS,{ variables:{ id: gameResults.length+1, player: newData[0], results: newData[1] } }) useEffect(() => { setNewData(props.winner.split('$')) if (data) { setResults(data.getResults); } }, [data]); if (loading) return <>'...'</>; return ( <div> <table> <thead> <tr> <th>Player Won</th> <th>Board Results</th> </tr> </thead> <tbody> {gameResults && gameResults.length > 0 && gameResults.map((game) => <tr key={game.id}> <td>{game.player}</td> <td>{game.results}</td> </tr>)} </tbody> </table> {dataMutation && dataMutation.createGameResults ? <button onClick={()=>window.location.reload()} className='start-new-game'>Play Again</button> : <button className='saveResults' onClick={()=>{createGameResults(); refetch()}}>Save Results</button> } </div> ) } export default Results;
בשורה 16 אנחנו בונים את השאילתה בדומה לבניה שעשינו בשיעורים הקודמים (למעשה העתק הדבק של השאילה של mutation). וניתן לה שם בהתאמה (ADD_GAME_RESULTS)
ואז בשורה 29 קורה הקסם של GQL . הפעם המידע שחוזר הוא מערך, האייטם הראשון הוא פונקציה שמפעילה את ה mutation. קראתי לה createGameResults, ובהמשך את האובייקט של מה שנרצה , לא חייבים , אני בחרתי להביא את המידע שחוזר ואת הerror , אני לא עושה שימוש בerror זה רק לצורך הדוגמה. אז נעביר את השאילתה דרך useMutation וגם עוד משהו נוסף שיעביר את המידע לresolve שבנינו בצד השרת, ונעביר את המידע שאנחנו מצפים לקבל, שזה ID , PLAYER , RESULTS.
כמו כן , נוסיף את כל הפונקציוליות שלנו לשימוש היוזר בתוך הUI שלנו, שימו לב לשורה 62-64 , ישנו כפתור שמריץ את הפוקציה שמפעילה את הmutation ( createGameResults ) והיא מעבירה את המידע החדש ושומרת אותו בתוך המערך של הנתונים (כרגע נשמר בקאש שמנוהל על ידי GQL – בהמשך נעביר הכל לדטה noSQL) יש תנאי על הכפתור על מנת למנוע לחיצה כפולה ושליחה כפולה של המידע . לאחר שמירה אחת הכפתור הופך לכפתור שמתחיל את המשחק מהתחלה play again).
דבר נוסף וחשוב שבטח שמתם לב הוא refetch , זוהי פונקציה נוספת שהינו מובנית שעושה הבאה של הדטה מחדש , למעשה מריצה שוב את השאילתה של query ומעדכת את הטבלה, אחרת לא תראה את הטבלה מתעדכנ אלא רק לאחר רפרוש של עמוד כולו .
יכול להיות שתראו עוד כמה דברים כמו איזה props שאני מעביר זה רק לטובת הצגה של המנצח במשחק ככותרת (פחות רלוונטי ולא עושה שוב שימוש עם GQL אז אני לא מציין מה זה עושה כי זה סתמי ובטח דיי מובן).
לסיכום שיעור על react ו apollo clinet
ראינו איך אפשר לייבא מידע ואיך אפשר להוסיף מידע, באופן דומה למה שהצגנו פה אפשר גם לעדכן מידע או למחוק מידע (Mutation כמובן) ויש עוד הרבה דברים שאפשר לעשות עם apollo client . מכוון שקורס זה הוא ביסיס וקצת לא אכנס לכל הפרטים. מה שכן , אני אמשיך לעוד שיעור שבו נגדיר איזה דטה בייס שישמור את הנתונים ונמשוך אותם משמה לתוך האפליקציה שלנו. ושיעור אחרון יהיה שיעור האשרה ואנחנו ממש לקראת סיום קורס חינם בreact וGQL . 🐊❤

