הפעם נדבר על שני הוקים, בפוסט אחד, מכוון ששני ההוקים הללו מאד דומים.
נתחיל בהסבר קצר, שימוש של useMemo , useCallback
בריאקט יש את הנושא של רינדור הקופוננטה , שבוודאי נתקלתם במצבים ששמתם קונסולוג ברכיב ומשומשה, כמעט בכל פעולה ברכיב ראיתם את ההדפסה לקונסול גם אם לא הייתה באמת סיבה לכך. זה מכיוון שבריאקט כל שינוי ברכיב , הרכיב מתרנדר שוב ולכן זו הסיבה להרצות מיותרות. וכן, ריאקט מימשה שני הוקים שעוזרים לטפל בבעיה, שניהם עושים את אותו הדבר מלבד הבדל אחד,
useMemo – מחזיר את ההערך שחוזר מהפונקציה
useCallback – מחזיר את הפונקציה עצמה
מאמין שחלקכם חשבתם זה : שאולי כדאי לעטוף כל פונקציה ב useMemo , useCallback , אבל זה לא הכי מומלץ כי אז תצוץ בעיית זכרון מכוון שהוקים אלו עושים שימוש בקאש, ולכן ההמלצה היא להשתמש בהם יש ריצות שכן קצת כבידות במימושם ובכך להקל על הביצועים.
בואו ניגש לדוגמאות ונסביר אותן ואז הכל יהיה ברור:
דוגמה ל useMemo
import React, { ReactElement, useContext, useState,useMemo } from 'react'; import logo from './logo.svg'; import './App.css'; import ButtonClicked from './buttonClicked'; import { Context } from './context'; import AddMoreCrocs from './addMoreCrocs'; function lazyCrocs(nubmerOfCrocs: number) : number{ for(let i = 0 ; i < 100000; i++) {} console.log('crocs are lazy'); return nubmerOfCrocs*3 } function App(props: any): ReactElement<any> { const {startTheGame} = useContext(Context); const [number, setNumber] = useState(Math.random()*10); const nubmerOfCrocs = useMemo(() => lazyCrocs(number), [number]); const [gameStatus, setGame] = useState(false); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <ButtonClicked /> <button onClick={()=>{startTheGame(gameStatus);setGame(!gameStatus)}}>Start the Game</button> </header> <div>{nubmerOfCrocs}</div> <div className="addMoreCrocs"> <AddMoreCrocs /> </div> </div> ); } export default App;
אפשר לראות שימוש בuseMemo . נראה מאד פשוט, אם לא נשתמש בuseMemo מה שיקרה זה שכל פעם שמשהו ישתנה באפליקציה, הפונקציה תרוץ ותדפיס לנו crocs are lazy. וכפי שאפשר לראות הפונקציה עושה עבודה בקטנה (סתם לופ ריק לצורך ההמחשה) אז חבל להריץ אותה שוב ושוב ולכן נשתמש ב בuseMemo .
useMemo יקבל את הפונקציה ומערך של המשתנים שהוא יאזין להם, אם האחד מהמשתנים ישתנה, אז הפונקציה תרוץ שוב. אם שמתתם מערך ריק , היא לא תאזין לשום שינוי, ותרוץ פעם אחת בהתחלה וזהו.
דוגמה ל useCallback
import React, { ReactElement, useContext, useState,useCallback } from 'react'; import logo from './logo.svg'; import './App.css'; import ButtonClicked from './buttonClicked'; import { Context } from './context'; import AddMoreCrocs from './addMoreCrocs'; function lazyCrocs(nubmerOfCrocs: number) : number{ for(let i = 0 ; i < 100000; i++) {} console.log('crocs are lazy'); return nubmerOfCrocs*3 } function App(props: any): ReactElement<any> { const {startTheGame} = useContext(Context); const [number, setNumber] = useState(Math.random()*10); const nubmerOfCrocs = useCallback(() => lazyCrocs(number),[number]); const [gameStatus, setGame] = useState(false); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <ButtonClicked nubmerOfCrocs={nubmerOfCrocs} /> <button onClick={()=>{startTheGame(gameStatus);setGame(!gameStatus)}}>Start the Game</button> </header> <div className="addMoreCrocs"> <AddMoreCrocs /> </div> </div> ); } export default App;
מאד דומה לדוגמה של useMemo רק ש useCallback מחזיר את כל הפונקציה ולא רק את הערך שחוזר ממנה, כך שאפשר להעביר את הפונקציה ולעשות בה שימוש בפרופס (למשל בדוגמה).
לסיכום useMemo useCallback
הוקים אלו מאד שימושיים , תוכלו למצוא גם שימושים נוספים עם הוקים אלו (למשל referential equality). יש לבחור בין ההוקים הללו בהתאמה , למרות ההבדלים הקטנים אתם תגלו כי כן יש מצבים שתרצו להשתמש useMemo ולא ב useCallback ולהיפך .
לרוב uesMemo ישמש להימנע מהרצות כבידות של ביצועים ברכיב . בעוד ש useCallback יהיה במקרים ספציפיים של מקרים משולבים ומעברים של בין קומפוננטות שונות.
ההוק הבא, הפוסט הבא, יהיה useRef.