הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

שלושים שעות עבודה ברצף הן לא הפיתרון

05/07/2021

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

"העבודה הראשונה שלי היתה בבנק מורגן סטנלי. הייתי בפיגור מבחינת הביצועים שלי באוניברסיטה בהשוואה לאנליסטים המתחילים האחרים. בכל שבוע שני היה לי מנהג: הייתי מגיע לעבודה ביום שלישי בבוקר ויוצא משם רק ביום רביעי בלילה. לא היה אף אחד שחיכה לי בבית, ולא היו לי תחביבים של ממש. לאדם בשנות ה–20 לחייו לא צריך להיות בעיה לעבוד יותר מ–30 שעות ברצף — אלא אם הוא בוחר לשכנע את עצמו אחרת".

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

המפתח שעוזר לנו להגיע להצלחה ולהרוויח טוב הוא ההבנה שהשוק מתגמל על מיומנות, ולפחות בתחום שלנו של פיתוח תוכנה, מתכנתת מיומנת תוכל להרוויח משמעותית יותר ממתכנתת פחות מיומנת או בתחילת הדרך - עד כדי פערים של פי 2, 3 או אפילו פי 5 לשעת עבודה. אם תשקיעו 60 שעות בשבוע בעבודה שמכניסה 100 ש"ח לשעה תרוויחו בכל חודש 27,000 ש"ח. לעומת זאת אם תשקיעו שנה שלמה בלימוד ושיפור מיומנות תוכלו למצוא עבודה ב 500 ש"ח לשעה ועכשיו ב 20 שעות עבודה בשבוע בלבד אתם מרוויחים 45,000 ש"ח בחודש.

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

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

תמונת סיום

04/07/2021

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

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

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

ניקח דוגמה קטנה שתעזור להבין על מה מדובר פה. דמיינו את עצמכם עובדים כבר 8 שנים באותה עבודה בתחום שהולך ודועך, אין לכם עניין מקצועי ואתם שם רק מטעמי נוחות, ודי בטוחים שלא הרבה מחכה לכם בחוץ. מפה לשם אתם פוגשים לקפה חברה שבדיוק סיימה לימודי Data Science והתקבלה לעבודה בתחום. היא מספרת על כל הדברים הטובים בעבודה החדשה: על התנאים, המשכורת, על אינסוף הצעות עבודה שהיא מקבלת כל שבוע מחברות מתחרות, על העניין והאתגרים המקצועיים בעבודה.

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

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

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

למה אני לא תמיד רושם מפתחות בלולאה ב React

03/07/2021

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

Warning: Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.

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

ההודעה על המפתחות החסרים בתוכנית ריאקט היא לא מהמקרים האלה.

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

function ComponentWithWarning() {
    const items = [10, 20, 30];
    return (
        <ul>
            {items.map(i => <li>{i}</li>)}
        </ul>
    );
}

function ComponentWithoutWarning() {
    const items = [10, 20, 30];
    return (
        <ul>
            {items.map((i, index) => <li key={index}>{i}</li>)}
        </ul>
    );
}

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

כאן יש דוגמה לקוד ריאקט שבור שהבאג בו הוא היעדר מפתחות יציבים, ואין בו שום אזהרה בקונסול כי הוא משתמש באינדקס בתור מפתח: https://jsbin.com/wohima/edit?output

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

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

ולגבי האזהרה הרגילה של ריאקט? אני תמיד מעדיף אותה על פני כתיבת key={index} כי היא מזכירה לי שאין לי כרגע מפתח יציב ושאם ארצה להוסיף קוד שמשנה את סדר האלמנטים כדאי שאבחר קודם כזה מפתח.

איך להציג עץ ב React עם טבלה ו React.Fragment

02/07/2021

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

המשך קריאה

מייל חודשי אחרון

01/07/2021

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

המשך קריאה

יותר מדרך אחת

30/06/2021

מה הדרך הכי טובה לבנות מערכת? מה הדרך הכי טובה להתקבל לעבודה בהייטק? מה הדרך הכי טובה ללמוד טכנולוגיה חדשה?

לכבוד ההנפקה של דואולינגו הערה שהופיעה בהאקרניוז תפסה אותי היום לא מוכן. הכותב הסביר כמה קשה ללמוד דרך דואולינגו ואיך הלימוד בפימסלר היה עבורו הרבה יותר רלוונטי. איך זה יכול להיות, רציתי לשאול אותו (או אותה)?! הרי לי היה ניסיון בדיוק הפוך עם שני הכלים.

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

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

צרות של כולם

29/06/2021

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

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

והרגלים (Habbits) נותנים לנו המתכנתים את היכולת להשתמש בתשתיות בצורה מיטבית. ההרגל להתחיל את היום בחצי שעה למידה; ההרגל להריץ את הבדיקות ולהסתכל בתוצאות שלהן כל פעם שמסיימים לעבוד על משהו; הרגלי עבודה בתוך IDEs חכמים ויכולת לקרוא מהר את הנתונים של אינסוף הכלים שעומדים לרשותנו. ההרגל לכתוב הודעות קומיט מועילות ולהסתכל בהודעות קומיט ישנות כדי להבין את ההיגיון מאחורי הקוד.

קשה לבנות תשתיות טובות וקשה עוד יותר לבנות הרגלים טובים, ובדיוק בגלל זה אנחנו חייבים.

היום למדתי: איך להתעלם מקומיטים ב git blame

28/06/2021

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

אבל-

לפעמים יש קומיטים שמשנים שורות בלי שהשינוי הזה באמת יהיה קשור לתוכן של אותה שורה. הדוגמה הקלאסית היא שינויים שמשנים טאבים לרווחים, אבל אפשר לחשוב גם על אישהו Refactoring שעשה Mass Rename לשם של פונקציה. במצב כזה הפעלה של git blame תציג לי את הקומיט העדכני ביותר, למרות שזה לא הקומיט אותו אני מחפש.

דוגמה קצרה תעזור להמחיש את העניין. נניח שיש לי קובץ Python עם התוכן הבא:

def twice(x):
    return x * 2


if __name__ == "__main__":
    x = int(input("Pick a number: "))
    print(f"{x} x 2 = {twice(x)}")

ואני רוצה לדעת למה הודעת ההדפסה מציגה דווקא את הסימן x כדי לסמן מכפלה. פקודת git blame היתה יכולה לעזור לי:

$ git blame a.py
7391c20d (ynonp 2021-06-27 14:39:12 +0300 1) def twice(x):
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 2)     return x * 2
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 3) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 4) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 5) if __name__ == "__main__":
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 6)     x = int(input("Pick a number: "))
7391c20d (ynonp 2021-06-27 14:39:12 +0300 7)     print(f"{x} x 2 = {twice(x)}")
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 8) 

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

$ git show 7391c20d

commit 7391c20df9f8eec472494602ffa727542151c553 (HEAD -> main)
Author: ynonp <ynonperek@gmail.com>
Date:   Sun Jun 27 14:39:12 2021 +0300

    Renamed function

diff --git a/a.py b/a.py
index 6e899d5..a883ec7 100644
--- a/a.py
+++ b/a.py
@@ -1,8 +1,8 @@
-def double(x):
+def twice(x):
     return x * 2


 if __name__ == "__main__":
     x = int(input("Pick a number: "))
-    print(f"{x} x 2 = {double(x)}")
+    print(f"{x} x 2 = {twice(x)}")

נו זה לא עזר במיוחד - מסתבר שהשינוי האחרון על השורה היה בסך הכל שינוי שם של הפונקציה. בשביל להמשיך לקומיטים ישנים יותר ב blame אני משתמש במתג ignore-rev:

$ git blame --ignore-rev 7391c20d a.py
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 1) def twice(x):
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 2)     return x * 2
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 3) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 4) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 5) if __name__ == "__main__":
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 6)     x = int(input("Pick a number: "))
373b123e (ynonp 2021-06-27 14:38:12 +0300 7)     print(f"{x} x 2 = {twice(x)}")
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 8) 

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

$ git show 373b123e

commit 373b123e76b02fe6972de79daf52839f5b08664a
Author: ynonp <ynonperek@gmail.com>
Date:   Sun Jun 27 14:38:12 2021 +0300

    Changed multiplication symbol

    Turns out we've received multiple complaints about clients
    not understanding that a * is actually a multiplication sign,
    so product asked to replace the * with an "x"

diff --git a/a.py b/a.py
index 9cc6552..6e899d5 100644
--- a/a.py
+++ b/a.py
@@ -4,5 +4,5 @@ def double(x):

 if __name__ == "__main__":
     x = int(input("Pick a number: "))
-    print(f"{x} * 2 = {double(x)}")
+    print(f"{x} x 2 = {double(x)}")

עכשיו בדוגמה שלנו הקומיט ששינה את שם הפונקציה בהחלט יכול להועיל בקונטקסט אחר, אבל יש מקרים (כמו שינוי טאבים לרווחים) שהקומיט אף פעם לא יועיל - ומה שצריך זה פשוט להתעלם ממנו בכל blame שאי פעם נריץ.

בשביל זה אנחנו יוצרים קובץ בתיקיית הפרויקט (אפשר לבחור לו כל שם, אני קראתי לו .git-blame-ignore-revs), ורושמים לתוכו את המזהה ממנו רוצים להתעלם:

$ echo 7391c20df9f8eec472494602ffa727542151c553 >> .git-blame-ignore-revs 

(שימו לב לרשום לקובץ את מזהה הקומיט המלא ללא קיצורים)

אחר כך מגדירים קונפיגורציית גיט שתתעלם אוטומטית מכל ה Revisions בקובץ זה:

$ git config blame.ignoreRevsFile .git-blame-ignore-revs

ו-הפתעה. עכשיו כשנפעיל git blame הקומיט הבעייתי לא יופיע ונגיע ישר לקומיט שמעניין אותנו:

$ git blame a.py

cae63ff (ynonp 2021-06-27 14:36:40 +0300 1) def twice(x):
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 2)     return x * 2
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 3) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 4) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 5) if __name__ == "__main__":
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 6)     x = int(input("Pick a number: "))
373b123e (ynonp 2021-06-27 14:38:12 +0300 7)     print(f"{x} x 2 = {twice(x)}")
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 8) 

ואגב אחרון, אם עשיתם את כל ההוראות לפי הפוסט ועכשיו דווקא מתחשק לכם לוותר על הדילוג ולראות את git blame האמיתי תוכלו תמיד להפעיל:

$ git blame --ignore-revs-file "" a.py

7391c20d (ynonp 2021-06-27 14:39:12 +0300 1) def twice(x):
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 2)     return x * 2
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 3) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 4) 
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 5) if __name__ == "__main__":
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 6)     x = int(input("Pick a number: "))
7391c20d (ynonp 2021-06-27 14:39:12 +0300 7)     print(f"{x} x 2 = {twice(x)}")
^cae63ff (ynonp 2021-06-27 14:36:40 +0300 8) 

ללמוד מניסיון של אחרים

27/06/2021

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

קחו את ההרצאה הזאת של Sha Ma מ Github מכנס Qcon 2020 (היסטוריה עתיקה אני יודע, ובכל זאת). היא מספרת על המעבר של גיטהאב לארכיטקטורה היברידית, מונולית + מיקרו סרביסס. היא מספרת על הקשיים, על הכלים בהם הם השתמשו ועל האסטרטגיה בה הם בחרו. ההרצאה מספקת הזדמנות להיות זבוב על הקיר בחדר הישיבות של גיטהאב כדי להבין לא רק את ה"איך" אלא גם את ה"למה".

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

פיתרון חידת ריאקט מאתמול

26/06/2021

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

import "./styles.css";

import React, { useRef, useState } from "react";

export default function Targil1(props) {
  const inputCount = 4;

  const [inputsText, setInputsText] = useState(new Array(inputCount).fill(""));

  const inputsRef = [];

  for (let i = 0; i < inputCount; i++) {
    inputsRef.push(useRef(null));
  }

  const containerDiv = {
    display: "flex"
  };

  function ChangeValueAndFocus(index, e) {
    inputsText[index] += e.key;

    inputsRef[(index + 1) % inputCount].current.focus();

    setInputsText([...inputsText]);
  }

  return (
    <div style={containerDiv}>
      {inputsText.map((item, index) => (
        <input
          value={item}
          key={index}
          autoFocus={index === 0 ? true : false}
          ref={inputsRef[index]}
          onKeyPress={(e) => ChangeValueAndFocus(index, e)}
        />
      ))}
    </div>
  );
}

וזה בקודסנדבוקס: https://codesandbox.io/s/tender-curie-ux3g5?file=/src/App.js

המשך קריאה