במאמר זה אנו נדון מה זה Redux, למה אנחנו צריכים אותה ומתי משתמשים בה. לאחר מכן נראה כיצד ליישם Redux Toolkit (הגרסה החדשה) עם TypeScript ב-React.js.
מה זה Redux?
Redux היא ספריית JavaScript פופולרית שמשמשת לניהול מצב / מידע באפליקציה בצורה מסודרת ומובנת (state management). לדוגמה, באתרי E-commerce משתמשים ב-Redux כדי לשמור ולנהל מגוון פעולות שאנחנו עושים באתרים מסוג זה, לדוגמה ניהול המוצרים שהוספנו לסל, ניהול כמות המוצרים שיש לנו בסל, ניהול השילוח וכדומה.
הטרמינולוגיה של Redux:
Redux מורכבת משלושה יחידות שפועלות ביחד על מנת ליצור זרימה וניהול תקין של אותן הנתונים / מצב:
Store:
store היא אובייקט המחזיק את כל הנתונים ומצב האפליקציה. ה-store הוא ה-single source of truth. מכאן נשאב את הנתונים שאספנו מהאתר ונזרים אותם לשאר חלקי האפליקציה שצריכים את אותו מידע.
Actions:
actions הם אובייקט שמייצגים את הכוונה לשנות את מצב האפליקציה. לכל action יש מאפיין 'type' המתאר את הפעולה שהוא ירצה לבצע ומאפיין(אופציונלי) 'payload' המכיל נתונים נוספים הדרושים לביצוע הפעולה. בגרסה החדשה של Redux שאותה נלמד היום(Redux Toolkit) לא חובה לתת type, המאפיין type יהיה לפי שם ה-slice's name (שעליו נלמד) + השם של הפונקציה: counter/incrementByAmount.
Reducers:
reducers הם פונקציות שלוקחות את המצב הנוכחי של האפליקציה (state) ו-action(אופציונלי) כארגומנטים ומחזירות מצב חדש(מעודכן) על סמך הלוגיקה של ה-Reducer Function. בגרסת ה-Redux Toolkit, יש שם שחקן חדש שנכנס לתמונה שמאגד את כל ה-actions ופונקציות ה-reducers והוא נקרא createSlice. לכל Slice יש מספר מאפיינים שעוזרים לנו לנהל את המידע ולבצע מניפולציות על המידע בצורה מסודרת יותר:
מה בדרך כלל createSlice מכיל:
name - שם ה-slice ומשמש ליצירת type לכל action באופן אוטומטי.
initialState - המידע הראשוני שצריך להיות באותו reducer, איזשהו מידע שחייב להיות לו כבר ברגע הראשון. לדוגמה, אם נרצה על כל לחיצה להגיל ב-1 את המספר, זה אומר שבהתחלה אמור להיות ערך התחלתי כמו 0:
reducers - אובייקט שמכיל את ה-action וגם את ה- reducer functions. הם בעצם key value pair; ה-key זה שם ה-actions וה-value זה ה-reducer functions.
extraReducers - שבו אתם יכולים להגדיר (לא חובה) actions ו-reducer functions שלא הוגדרו ב-reducers אובייקט אלא הוגדרו ב-slice אחר או מחוץ לאובייקט createSlice.
לפני שנראה את התמונה של כולם ביחד, אנחנו רוצים לדבר אתכם על האפשרות של לבצע קריאות API עם Redux Toolkit.
createAsyncThunk:
באפשרותנו להשתמש (לא חובה) בפונקציה createAsyncThunk שמאפשרת טיפול פשוט יותר בבקשות לשרת וטיפול בשגיאות, ומשפר את ארגון הקוד. פונקציה זו באופן אוטומטי נותנת לכם גישה לשלושת המצבים בהם יכולה הבקשה שלכם להיות (pending, fulfilled and rejected).
יישום Redux Toolkit עם TypeScript:
לפני שאתם רואים את התמונות, אנחנו ממליצים לקורא את המאמר הזה לפחות פעמיים כדי להבין את Redux & Redux Toolkit. זה מנגנון שיכול להיות מסובך להבנה בפעם הראשונה, לכן קריאה שנייה בהחלט תתרום לכם. על כל שורת קוד, הוספנו הערה שתעזור לכם להבין טוב יותר את הקוד שלנו.
שלב ראשון - הורדת ה-packages:
npm i @reduxjs/toolkit
npm i react-redux
שלב שני - יצירת תיקיות וקבצים לניהול תקין של Redux Toolkit:
app\hooks.ts
app\store.ts
features\counter\slice.ts
features\counter\api.ts
index.tsx
features\counter\Counter.tsx
בקובץ הראשון: hooks.ts
בקובץ השני: store.ts
בקובץ השלישי: slice.ts
בקובץ הרביעי: api.ts
בקובץ החמישי: index.tsx
בקובץ השישי: Counter.tsx
בקובץ הזה אנחנו רוצים שתשימו לב לשני דברים:
useAppSelector - נועד כדי למשוך פיסת מידע מה-store שלנו.
useAppDispatch - מחזיר פונקציה (dispatch) שנועדה לבצע קריאה ל-actions שהגדרנו.
סיכום מערכת Redux:
כאשר אנו רוצים להשתמש בנתונים מסוימים מה-Store, נשתמש ב-hook בשם useAppSelector, ונקבע בתוכו את ה-selectorState הרלוונטי, במקרה שלנו – selectCount.
על מנת לעדכן את הנתונים הקיימים ב-Store, נשתמש ב-hook בשם useAppDispatch, שמחזיר פונקציה בשם dispatch.
כפי שניתן לראות בשורות 34, 44, 60 ו-67, אנו משתמשים ב-dispatch ומעבירים לה את ה-action המתאים, הכולל שני תכונות – 'type' ו-'payload'.
כל action כולל את תכונת 'type' המתארת את הפעולה שיש לבצע(אם לא מגדירים type, יש type ברירת מחדל), ותכונה (אופציונלית) בשם 'payload', המכילה נתונים נוספים הדרושים לביצוע הפעולה.
לאחר שקראנו ל-action המתאים, התהליך ממשיך ל-reducer, שבוחר את ה-action הרלוונטי ומבצע את העדכון המבוקש.
כשהעדכון הושלם, הנתונים המעודכנים מגיעים לכל קומפוננטה המשתמשת באותם הנתונים, ולאחר מכן מתבצע רינדור (ריענון) של הקומפוננטות המעורבות.
Context API VS Redux
לפעמים עולה שיח למה אנחנו צריכים להשתמש ב-Redux Toolkit כשיש לנו Context API. בואו ננסה לענות על השאלה הזו בקצרה:
Context API פשוט וקל יותר לשימוש והקמה, בעוד Redux דורש יותר קוד ועקומת למידה תלולה יותר.
Context API מובנה בתוך React, בעוד ש-Redux היא ספרייה נפרדת שצריך להתקין ולהגדיר.
Context API מתאים יותר לאפליקציות קטנות עד בינוניים, בעוד ש-Redux מיועד לאפליקציות גדולות ומורכבות עם יותר זרימה של נתונים.
ל-Redux יש מספר אופטימיזציות מובנות של ביצועים כדי למזער רינדורים מיותרים, בעוד של-Context API אין אופטימיזציות כאלו.