הצעה לפרויקט - יישום צ'ט ב React ו Redux

21/08/2020

החל מהבוטקמפ הבא אני מתכנן לשנות קצת את המתכונת ולהוסיף 5 שבועות עבודה על פרויקט בסוף ה-3 שבועות של הלימוד התיאורטי. אנחנו נצטרך לחכות ולראות איך זה יעבוד לתלמידים אבל בינתיים הנה דוגמה לפרויקט שאני מתכנן למחזור הבא של קורס ריאקט. מוזמנים לפתור אותו גם אתם בהזדמנות כשיהיה לכם זמן פנוי - הוא בוודאות יעזור לכם להבין טוב יותר את הארכיטקטורה של ריאקט ו Redux

(וכן אני יודע שאתם אוהבים מובאקס. הכל טוב גם אותו אני מלמד ויש פרויקטים גם עליו. תתפלאו אבל יש לא מעט אנשים שעדיין מעדיפים את Redux).

1. צעד ראשון - ממשק וקומפוננטות

אני אוהב להתחיל פרויקט ריאקט במחשבה על הממשק. במקרה של צ'ט אני חושב על מסך פתיחה בו אפשר לבחור שם משתמש ולפתור קאפצ'ה, ואחריו נכנסים למסך השיחה שכולל תיבת צד עם רשימת חדרי השיחה ואזור מרכזי עם השיחה עצמה שבחדר.

בשביל מסך הכניסה מספיק חלון פשוט כמו בדוגמא כאן (רק צריך לשים קאפצ'ה במקום הסיסמה): https://bootsnipp.com/snippets/dldxB

ולמסך הצ'ט הייתי לוקח עיצוב בסגנון הזה: https://bootsnipp.com/snippets/nNg98

מזה אפשר לבנות קומפוננטות עצמאיות להצגת המידע, לדוגמא:

  1. קומפוננטה לטופס הכניסה

  2. קומפוננטה למסך הצ'ט הראשי

  3. קומפוננטה להצגת רשימת החדרים

  4. קומפוננטה להצגת רשימת הודעות (למשל בתוך חדר שיחה)

  5. קומפוננטה לתיבת כתיבה ושליחת הודעה חדשה

  6. קומפוננטה להצגת הודעה בודדת

  7. קומפוננטה של כותרת חדר שכוללת תמונה, טקסט ושלוש נקודות שכשלוחצים עליהן ייפתח תפריט עם עוד כמה פעולות (אולי להוריד את כל תוכן השיחה לקובץ או למחוק הודעות).

בגלל שאנחנו בתרגיל Redux הנחת העבודה שלי שכל ההודעות וחדרי השיחה יישמרו באוביקט Redux גלובאלי. זה אומר שבעת כתיבת הקומפוננטות אני כמעט לא משתמש בסטייט מקומי לקומפוננטה, והכי חשוב כל קומפוננטה מקבלת בתור props את המידע שהיא צריכה להציג. בשלב הזה אני עדיין לא מנסה להבין מאיפה המידע יגיע, פשוט רוצה להציג אותו בצורה הטובה ביותר.

אם ניקח לדוגמא קומפוננטה של חדר שיחה אפשר לדמיין שהקומפוננטה תקבל בתור Property את רשימת ההודעות שבחדר וכל תפקידה להציג קומפוננטה של כותרת לחדר, אחריה את רשימת ההודעות ובסוף קומפוננטה של כתיבת הודעה חדשה. אפשר לפתח את הקומפוננטה ולראות את ההודעות על המסך לפני שבכלל מתחילים לבנות את הלוגיקה.

כן כדאי כבר בשלב הזה לבנות את הלוגיקה שרלוונטית לקומפוננטות. לדוגמא כשנסתכל על קומפוננטת כותרת החדר אנחנו רואים בצד ימין אייקון שלוש נקודות ואפשר לדמיין שכשלוחצים עליו יופיע תפריט עם אפשרויות לחדר. את זה אפשר לכתוב בתור State פנימי של הקומפוננטה ואת כל המנגנון כולל הצגת התפריט והסתרה שלו הייתי בונה בשלב הזה כשבונה את הקומפוננטה לכותרת החדר.

2. צעד שני - תמיכה בשיחה מקומית

אחרי שהקומפוננטות מוכנות אפשר לחבר את החוטים ל Redux Store. מתחילים בליצור את ה Reducer וה Store, חושבים איך רשימת כל ההודעות תישמר בתוך אוביקט המידע (אני הייתי הולך על מערך שטוח של הודעות, ובכל הודעה שומר מאפיין מאיזה חדר היא הגיעה), ואיזה עוד מידע נשמר באוביקט הגלובאלי.

ממשיכים לבניית קוד ה Reducer ותמיכה בפעולות. זיכרו ש Reducer בנוי בצורה של Action שהתקבל ומה ההשפעה של ה Action הזה על הסטייט הגלובאלי. אלה ה Actions הראשונים שהייתי בונה (יחד עם הטיפול בהן):

  1. משתמש נכנס למערכת עם שם משתמש מסוים

  2. הודעה חדשה התקבלה במערכת

  3. משתמש עבר לחדר שיחה אחר

  4. נוצר חדר שיחה חדש

  5. משתמש הצטרף לחדר שיחה

  6. משתמש עזב חדר שיחה

שלב אחרון לחלק הזה יהיה לחבר את הפעולות לקומפוננטות. הנה מספר דוגמאות:

  1. כשמשתמש מסיים לבחור שם משתמש בטופס הכניסה נבצע Dispatch לפעולה של "משתמש נכנס למערכת"

  2. כשמשתמש לוחץ על חדר שיחה ברשימת החדרים נבצע Dispatch לפעולת "משתמש עבר לחדר שיחה אחר"

  3. כשמשתמש שולח הודעה נבצע Dispatch לפעולת "הודעה חדשה התקבלה במערכת"

סיום החלק הזה יהיה אפליקציית צ'ט עובדת ומעוצבת אבל עדיין ברמה מקומית.

3. צעד שלישי - חיבור לשרת צ'ט

אחרי שיש לנו אפליקציית צ'ט מקומית אנחנו יכולים להמשיך לחבר אותה לשרת. החיבור לשרת מכניס לוגיקה אסינכרונית ליישום, ואני אוהב לבנות אותה באמצעות Middleware: נפתח Middleware חדש שמתקשר עם Firebase. בפעולות המתאימות נדווח ל Firebase שמשהו קרה, וכשנקבל עדכונים מ Firebase נוכל להעביר אותם ל Reducer שלנו.

לדוגמא כשה Middleware מקבל פעולת "הודעה התקבלה במערכת" הוא יודע שמשתמש מקומי הוסיף הודעה לחדר, ואז הוא יכול לשלוח את ההודעה גם לשרת Firebase. בצד השני כשה Middleware מקבל אירוע מ Firebase של הודעה חדשה התקבלה במערכת הוא יכול לבצע Dispatch חדש על ההודעה הזאת כדי שהיא תיכנס לקבל טיפול ב Reducer (תצטרכו רק לשים לב להוסיף שדה meta ל Action כדי להבדיל בין הודעה שהגיעה ממשתמש מקומי להודעה שהגיעה מרחוק, כדי לא לשלוח בטעות לפיירבייס הודעה שהם בדיוק שלחו לנו).

או דוגמא נוספת, כשה Middleware מקבל פעולת "משתמש שינה חדר שיחה" הוא יוכל לפנות לפיירבייס ולמשוך את כל ההודעות בחדר השיחה החדש ולהוסיף אותן למערכת, כדי שהמשתמש יראה את ההודעות בחדר החדש אליו עבר, ובאותה הזדמנות גם להתחיל להקשיב לאירועי "הודעות חדשות" בחדר השיחה החדש.

4. צעד רביעי - פינוקים

אם הגעתם לפה זה אומר שיש לכם אפליקציית חדרי שיחה מתפקדת שעובדת מול שרת Firebase ומסונכרנת בין מספר גולשים במקביל. זה מדהים!

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

  1. צירוף קובץ לחדר שיחה

  2. בחירת תמונת פרופיל לכל משתמש

  3. לוגין דרך שירותים חיצוניים (פייסבוק, גוגל, גיטהאב)

  4. תמיכה ב Markdown במסך עריכת ההודעה

  5. פתיחת "שרת צ'ט" פרטי רק עבור צוות או קבוצה מסוימים

והמשך רעיונות ככל שהדימיון שלכם לוקח אתכם.