Redux Toolkit עם TypeScript: המדריך המלא

Logo of Redux Toolkit

במאמר זה אנו נדון מה זה Redux, למה אנחנו צריכים אותה ומתי משתמשים בה. לאחר מכן נראה כיצד ליישם Redux Toolkit (הגרסה החדשה) עם TypeScript ב-React.js.

מה זה Redux?

Redux היא ספריית JavaScript פופולרית שמשמשת לניהול מצב / מידע באפליקציה בצורה מסודרת ומובנת (state management). לדוגמה, באתרי E-commerce משתמשים ב-Redux כדי לשמור ולנהל מגוון פעולות שאנחנו עושים באתרים מסוג זה, לדוגמה ניהול המוצרים שהוספנו לסל, ניהול כמות המוצרים שיש לנו בסל, ניהול השילוח וכדומה.

הטרמינולוגיה של Redux:

Redux מורכבת משלושה יחידות שפועלות ביחד על מנת ליצור זרימה וניהול תקין של אותן הנתונים / מצב:

  • Store:

    store היא אובייקט המחזיק את כל הנתונים ומצב האפליקציה. ה-store הוא ה-single source of truth. מכאן נשאב את הנתונים שאספנו מהאתר ונזרים אותם לשאר חלקי האפליקציה שצריכים את אותו מידע.

    Diagram illustrating the core principles of Redux
    By Mosh Hamedani
  • Actions:

    actions הם אובייקט שמייצגים את הכוונה לשנות את מצב האפליקציה. לכל action יש מאפיין 'type' המתאר את הפעולה שהוא ירצה לבצע ומאפיין(אופציונלי) 'payload' המכיל נתונים נוספים הדרושים לביצוע הפעולה. בגרסה החדשה של Redux שאותה נלמד היום(Redux Toolkit) לא חובה לתת type, המאפיין type יהיה לפי שם ה-slice's name (שעליו נלמד) + השם של הפונקציה: counter/incrementByAmount.

    JavaScript code snippet demonstrating the concept of actions in Redux Toolkit
  • 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

Code snippet from 'hook.ts' file showcasing the use of useAppDispatch and useAppSelector in Redux Toolkit

בקובץ השני: store.ts

Code snippet from 'store.ts' file showcasing how to configure the store in Redux Toolkit

בקובץ השלישי: slice.ts

Code snippet from 'slice.ts' file showcasing how to configure and build the slice in Redux Toolkit

בקובץ הרביעי: api.ts

Code snippet from 'api.ts' file demonstrating a mock async data request function

בקובץ החמישי: index.tsx

Code snippet from 'index.tsx' file demonstrating how to setup and connect the store to the application

בקובץ השישי: Counter.tsx

Code snippet from 'Counter.tsx' component, demonstrating how to use Redux Toolkit

בקובץ הזה אנחנו רוצים שתשימו לב לשני דברים:

  • 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 אין אופטימיזציות כאלו.