en
Feedback
ToCode

ToCode

Open in Telegram

טיפים קצרים למתכנתים מאת ינון פרק

Show more
1 419
Subscribers
No data24 hours
-17 days
+230 days
Posts Archive
ToCode
1 419
הקומפוננטה מציגה מונה וכל פעם שלוחצים על הכפתור הערך עולה ב-1. ביציאה מהדפדפן או טעינה מחדש של העמוד הערך של המונה נטען מ Local Storage וכך המונה ממשיך מאותה נקודה. סך הכל השימוש ב Hooks ב Vue מאוד פשוט. החיסרון היחיד שלו לדעתי בהשוואה לריאקט זה שהוא פחות מסודר: כל Hook יכול להאזין לכל אירוע Lifecycle ולהחליט מה עושים בתגובה לכל אירוע, בניגוד לריאקט שם הקוד מסודר כ"קוד להריץ בהתחלה" ו"קוד להריץ בסיום" בצירוף רשימה של תלויות. המבנה של Vue יותר פשוט לכתיבה אבל גם עלול ליצור באגים אם לא מטפלים נכון בכל האירועים.

ToCode
1 419
# שתי דוגמאות ל Vue Hooks כדי להבין איך זה עובד אחד הקונספטים שעבר כמעט בשלמותו מ React ל Vue היה ה Hooks, ובפרט הרעיון שאפשר לקחת לוגיקה שמשפיעה על State של קומפוננטה, להוציא החוצה את הלוגיקה ואת ה State שמחובר אליה לפונקציה חיצונית ואז להשתמש במנגנון מכל מיני קומפוננטות. בפוסט זה אני רוצה להראות שתי דוגמאות לכתיבת פונקציות חיצוניות כאלה ב Vue ודרכן את היכולות הריאקטיביות של הספריה. בדוגמה הראשונה נראה פונקציה שמחברת בין קומפוננטה לגודל החלון ובדוגמה השניה פונקציה ששומרת משתנה ב Local Storage כדי שהערך שלו תמיד ימשיך מאותה נקודה. ## הפונקציה useWindowSize בואו נניח שאנחנו רוצים לבנות קומפוננטה שמושפעת מגודל החלון. אולי אם יש לה יותר מקום היא תכלול יותר פרטי מידע או משהו בסגנון. יודעים מה? בואו נחלום בגדול ונניח שיש לנו 20 קומפוננטות לכתוב, כולן מושפעות מגודל החלון. דרך אחת (לא רעה) לנהל את זה היא לייצר Singleton ריאקטיבי ששומר אצלו את גודל החלון וכל הקומפוננטות ישתמשו במשתנים שמוגדרים שם. אנחנו פה בשביל לדבר על הדרך השניה, שהיא כתיבת Hook. הוק היא פונקציה שכל קומפוננטה יכולה להפעיל שיוצרת את המשתנים הריאקטיביים שמאזינים לשינויים בגודל החלון. ה Hook במקרה שלנו יכלול את הלוגיקה הבאה: 1. צור משתנה ריאקטיבי עם שני שדות עבור רוחב וגובה של החלון. 2. כשהקומפוננטה נכנסת לעמוד תוסיף Event Handler ל Window שכל פעם שהגודל שלו משתנה יעדכן את המשתנים הריאקטיביים. 3. כשהקומפוננטה יוצאת מהעמוד תמחק את ה Event Handler. סך הכל קוד הפונקציה נראה כך:

export function useWindowSize() {
  const size = reactive({ width: window.innerWidth, height: window.innerHeight });

  function handleResize() {
    size.width = window.innerWidth;
    size.height = window.innerHeight;
  }

  onMounted(() => {
    window.addEventListener('resize', handleResize);
  });

  onUnmounted(() => {
    window.removeEventListener('resize', resizeHandler);
  });

  return size;
}
ובשביל להשתמש ב Hook מתוך קומפוננטה אנחנו רק צריכים להפעיל את הפונקציה:
<script setup>
import { useWindowSize } from './hooks/hooks';

const size = useWindowSize();

</script>

<template>
  <div>
    <p>Window width = {{size.width}}; height = {{size.height}}</p>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

אם תנסו את זה אצלכם תוכלו לראות במרכז הקומפוננטה את הטקסט עם גודל המסך, וכל פעם שמשנים את גודל הדפדפן גם הטקסט יתעדכן בצורה אוטומטית. ## יצירת משתנה ריאקטיבי ששומר על ערכו עכשיו נניח שאתם רוצים להגדיר משתנה ריאקטיבי ששומר על ערכו אפילו אם משתמש סוגר את הדפדפן. דרך קלה לעשות את זה היא לשמור את הערך ב Local Storage, וכל פעם שהערך מתעדכן באופן אוטומטי לעדכן את המידע המתאים ב Local Storage. בעליה של הקומפוננטה נסתכל ב Local Storage ואם יש שם ערך נשתמש בו בתור ערך ראשוני למשתנה. הלוגיקה של ה Hook היא לכן: 1. ביצירת הקומפוננטה צור משתנה ריאקטיבי והתחל לעקוב אחר שינויים בו. 2. כל פעם שהערך משתנה כתוב את הערך החדש ל Local Storage. 3. ביציאת הקומפוננטה מהמסך הפסק להקשיב לשינויים במשתנה הריאקטיבי. הפונקציה היא לכן בסך הכל:
export function useLocalStorage(key, initialValue) {
  const value = ref(localStorage.getItem(key) || initialValue);
  const unwatch = watch(value, (currentValue, oldValue) => {
    localStorage.setItem(key, currentValue);    
  });

  onUnmounted(() => {
    unwatch();
    unwatch = null;
  });

  return value;
}
ובשביל להשתמש בה אפשר לכתוב קומפוננטה כמו זו:
<script setup>
import { useLocalStorage } from './hooks/hooks';

const value = useLocalStorage("counter", 0);

</script>

<template>
  <div>
  <button @click="() => value++">{{value}}</button>
  </div>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

ToCode
1 419
הדבר החשוב הוא לקחת את הרעיון הזה צעד קדימה ולראות מראש איזה לקוחות מחפשים דברים אחרים ממה שאתה מסוגל או רוצה לתת. ככל שלומדים לסנן את הפרויקטים האלה יותר מוקדם ככה אנחנו משאירים יותר זמן להתאמץ ולמצוא פרויקטים שכן רלוונטים לנו. ## לעבוד יותר שעות ורעיון אחרון שפשוט באופן עקבי לא עבד לי הוא לעבוד יותר שעות. כן, נקודתית אין ספק שאם יש לי פרויקט שבו אני מרוויח X ש"ח לשעה ואני אעבוד כפול שעות בשבוע אז ארוויח כפול באותו שבוע. אבל בראיה מערכתית זה פשוט קשקוש. בן אדם בלי מקצוע יכול לעבוד כשליח וולט ולהרוויח 50 ש"ח לשעה. אותו בן אדם אחרי שלמד תכנות יכול להרוויח על אותה שעת עבודה 500 ש"ח. כפרילאנסרים, הפוטנציאל שלנו להרוויח יותר לא טמון בלהוסיף עוד שעות עבודה בתור שליחים, אלא בלהפוך לאנשים שמסוגלים לקבל פרויקטים רווחיים יותר. זאת היתה הרשימה שלי, אם גם אתם עובדים כפרילאנסרים ויש לכם רעיונות שנראו לכם טובים אבל לא באמת עבדו כשניסיתם אותם מוזמנים בחום לשתף בתגובות.

ToCode
1 419
# רעיונות שלא עזרו לי להצליח כפרילאנסר בעשר שנים וקצת שאני עובד בתור פרילאנסר ניסיתי די הרבה רעיונות איך לשפר את העסק ובמיוחד איך לעשות יותר מהדברים שאני אוהב. רובם לא עבדו. בשביל שאתם לא תצטרכו לבזבז זמן על אותן שטויות, הנה סיכום של הרעיונות שנראו לי הכי טובים בזמנו אבל בתכל'ס לא עבדו בכלל: ## לעבוד דרך תיווך כשאתה מתחיל לעבוד בתור פאילאנסר אתה לא מכיר אף אחד ואף אחד לא מכיר אותך. ולא רק זה, אלא שגם אין לך מושג מה צריך לעשות בשביל להגיע ללקוחות. באותו זמן הרבה חברות וגם פרילאנסרים אחרים כן יודעים איך להגיע ללקוחות וכן יצרו כבר קשר ויחסי אמון עם לקוחות פוטנציאליים שלך. אותן חברות מציעות עכשיו עיסקה שקשה לסרב לה - אנחנו נחבר אותך ללקוחות שאתה מחפש בתמורה לאחוז מהכסף, ולהבטחה שלא תעבוד עם הלקוחות האלה בעתיד שלא דרכנו. הבעיה בשיטה הזאת היא שהיא בסך הכל דוחה את הקץ. יום אחד נצטרך ללמוד איך להגיע ללקוחות ואיך לבנות ערוצי שיווק יעילים. עד אז, כל יום שאתה מבזבז בעבודה דרך אותו מתווך זה יום שאתה לא עובד על פיתוח העסק שלך ובניית אותם ערוצי שיווק שיעזרו לך להגיע ללקוחות. יותר גרוע, כל יום שאתה עובד דרך אותם מתווכים אתה רק מחזק את ערוצי השיווק שלהם, בכך שאתה יוצר להם יותר לקוחות מרוצים. ## להעלות מחיר לפרויקט שאני לא רוצה לקחת אם הצלחת להתגבר על הפיתוי לעבוד דרך תיווך החבר הבא שצריך לדבר עליו הוא העבודה על פרויקטים שאתה יודע שהם לא נכונים עבורך. זה יכול להיות פרויקט בטכנולוגיה אחרת לגמרי מזו שאתה מכיר (ומזו שאתה רוצה להכיר), פרויקט ארוך או קצר מדי, פרויקט מול לקוחות שאתה יודע שלעולם לא יהיו מרוצים או אלף בעיות פוטנציאליות אחרות. כולנו מקבלים לפעמים טלפונים מלקוחות פוטנציאליים שאנחנו יודעים שלא יקדמו אותנו יותר מדי. לפעמים מישהו יציע לכם כשמגיע כזה פרויקט להעלות את המחיר, כדי לשקף את חוסר הרצון או את "עלות ההזדמנות" של אותו הפרויקט. לי השיטה הזאת לא עבדה אף פעם: אם הלקוח הסכים למחיר הגבוה הוא בדרך כלל ידרוש ממני הרבה יותר ממה שתכנן בהתחלה והפרויקט רק יהפוך לעוד יותר לא משתלם; אבל אפילו אם הלקוח לא הסכים למחיר הגבוה אנחנו נפרדים בהרגשה רעה כי נתתי לו מחיר כפול מכל ההצעות האחרות שהוא קיבל. כשיש פרויקט שלא מתאים לכם לעשות הדבר הכי הגון וטוב לעשות זה פשוט להגיד שכרגע זה לא מתאים לכם ואם אפשר לנסות למצוא ללקוח ספק אחר. ## להוריד מחיר לפרויקט שאני כן רוצה לקחת גם הצד השני של המשחק עם המחירים לא עבד לי אף פעם. כשניסיתי להוריד מחיר כדי "לקבל" פרויקט שרציתי, גיליתי בסוף שקרה אחד משני דברים: או שההצעה שלי נראתה ללקוח נמוכה מדי ולכן הוא העדיף לעבוד עם ספק אחר; או שהלקוח שמח לקבל את ההצעה הנמוכה ואני נתקעתי עם פרויקט שלא רק שהוא במחיר נמוך, אלא גם כשאותו לקוח ילך להמליץ לחברים הם יצפו לקבל גם אם אותו מחיר נמוך. אני זוכר מעט מאוד מקרים שהפסדתי פרויקט כי המחיר שהצעתי היה יקר מדי, ובמחשבה לאחור כולם היו לטובה. ## להתקמצן על הכסף של הלקוח נניח שלקוח מזמין אותי ליום ייעוץ אצלו בחברה כדי לפתור בעיית ביצועים ביישום ריאקט. אני יכול להגיע באוטובוס (שעה וחצי נסיעה, סיכוי לא רע לאיחור) או במונית (עשרים דקות נסיעה, משאיר זמן לקפה לפני שמתחילים). הבחירה להגיע במונית ולהוסיף את עלות המונית לעלות יום העבודה היא בחירה טובה יותר גם בשבילי וגם בשביל הלקוח. אני מגיע בזמן ומרוכז יותר, והלקוח מקבל ייעוץ אפקטיבי יותר. ## לנסות לשכנע אנשים שלא מקשיבים הרבה פעמים הייתי מגיע לשיחות מכירה עם לקוחות שפשוט לא רוצים לקנות את הדבר הזה שאני רוצה למכור להם. לדוגמה חבר עובד בחברה X שעכשיו בדיוק מחפשת חברת פיתוח שתבנה עבורם יישום לאייפון. החבר יודע שאני די טוב בתכנות ורק התחלתי לעבוד עכשיו כפרילאנסר אז הוא מחבר אותי לבן אדם הרלוונטי באותה חברה. הבעיה - אותו מקבל החלטות באותה חברה רוצה לעבוד עם חברת פיתוח גדולה ולא עם פרילאנסר כי הוא בטוח שחברות פיתוח גדולות נותנות יחס ושירות טוב יותר. אני יכול לשבת עם הבן אדם שעות ולהסביר על כל הניסיון שלי ולהראות את כל האפליקציות שבניתי, אבל זה פשוט לא יעזור. אותו מקבל החלטות מגיע עם קונספט מאוד ברור של מה הוא רוצה וזה פשוט לא הדבר שאני נותן. או - חברה מחפשת פרילאנסר שישב לעשות פרויקט אצלם במשרדים לתקופה של שלושה חודשים ואני כבר עובד על מספר פרויקטים ומעדיף לקחת את הפרויקט לעבוד עליו מהבית בנוסף לדברים האחרים שאני עושה. אני יכול עד מחר להסביר להם שצריך למדוד תפוקה ושאני יכול לבנות להם פיתרון מעולה בלי קשר לאיפה אני יושב, אבל בסוף אם הם נעולים על למצוא פרילאנסר שישב אצלם במשרדים זה פשוט לא יעזור.

ToCode
1 419
# לא באמת חדש שתי הזדמנויות לעבודה יותר יעילה- 1. לזהות בעיות שאתם כבר יודעים איך לפתור ולבנות להן פיתרון מהיר יותר (או הכי טוב - אוטומציה) 2. לזהות בעיות חדשות שהייתם צריכים כבר לדעת לפתור ולסווג אותן טוב יותר ניצול ההזדמנות הראשונה דורש שינוי מחשבה: במקום להסתכל על המשימה הנוכחית במנותק מהעולם, צריך להתחיל להסתכל על החיים בתור רצף של משימות שרובן חוזרות על עצמן. כל משימה שנצליח לפתור בצורה יעילה תחזיר את ההשקעה בזמן. ניצול ההזדמנות השניה דורש שינוי חשיבה מסוג אחר: במקום להתחיל מהפיתרון צריך להתחיל לחפש תבניות בבעיות עצמן כדי לזהות מתי פיתרון אחד יתאים למספר בעיות שונות, ואז לארגן מחדש את הבעיות כך שיתאימו לפיתרון שמצאנו. סקריפט שלוקח הקלטה של וובינר מזום ומעלה אותו לדף המתאים באתר חוסך לי עבודה כל שבוע ומחזיר מהר מאוד את הזמן שהשקעתי בכתיבה שלו. בניית תוכנית עבודה ללימוד נושא חדש עוזר לראות את האתגרים הדומים בלימוד נושאים חדשים ועוזר להסתכל על משימה כמו "לימוד פייתון" בתור משהו שאני כבר יודע לעשות. זה סוג של "ללמוד פרל" רק מספר אחר.

ToCode
1 419
# הזמנה לוובינר: צעדים ראשונים עם קוברנטס קוברנטס הוא אחת מהטכנולוגיות האלה שבקלות יכלתי לדלג עליה: מסורבלת פחות או יותר כמו שהיא פופולרית. כשלקוחות שאלו אותי על קוברנטס תמיד אמרתי שהרבה ממליצים אבל אני לא הכי מכיר. כשנתקלתי במדריך או Tutorial על קוברנטס הייתי שומר לי אותו בתיקיה מיוחדת בסימניות ומבטיח לעצמי לחזור אליו כשיהיה זמן (ויודע בלב שאף פעם לא יהיה). כל זה השתנה כשלקוח הציב מולי עובדה וביקש עזרה בהעלאת יישום לקלאסטר. כשניסיתי להגיד שאני לא מכיר קוברנטס ועדיף לפנות למישהו אחר התשובה היתה "אתה תלמד מהר". ובאמת הלכתי ללמוד, למרות שמהר זה לא היה. כי קוברנטס עם כל הרצון הטוב באמת קצת מסורבל והתיעוד באמת ארוך מדי ומסתבר שאפילו כל ה Tutorials האלה ששמרתי רק לימדו אותך איך להתקין קלאסטר, אבל לא ממש איך להעלות אליו יישומים. עכשיו כשאני כבר יודע קוברנטס (או לפחות מספיק ממנו בשביל להיות מועיל), אני רוצה לעזור למי מכם שמעוניין ללכת באותה דרך. לראות את הדברים היפים של קוברנטס מנקודת מבט של מפתחים בלי להתעסק באופטימיזציות (החשובות) מנקודת המבט של Devops. במילים אחרות להשתמש בקוברנטס בתור פלטפורמה להתקנה והרצת יישומים. והאמת שקוברנטס הוא אחלה פלטפורמה לזה. בין הדברים שאתם מקבלים מהקופסה יש: 1. הרצה אוטומטית של היישום שלנו בתוך קונטיינר, כולל הפעלה מחדש כשמשהו מתרסק והוספת שרתים אוטומטית כשיש עומס. 2. העלאת גירסה ב Zero Downtime Deployments. 3. שיכבת אבסטרקציה מעל שרתי ענן, כך שאפשר יהיה לעבור בין הענן של אמזון, גוגל או מייקרוסופט בלי לשנות שורת קוד ביישום. 4. אבסטרקציה של Cron Jobs ומעקב אחרי הג'ובים שרצו או נכשלו. 5. ניהול אוטומטי של "סודות". 6. ממשק ניהול גרפי שמראה לנו את כל מה שעובד או לא עובד בקלאסטר. סך הכל אחרי שמתרגלים העבודה עם קוברנטס היתה לי (ותהיה לכם) קלה יותר מאשר העלאת קונטיינרים ידנית לשרת או עבודה עם docker-compose. ביום חמישי הקרוב בשעה 10:00 בבוקר אני מתכוון להעביר בזום וובינר של שעה עם הסבר הכי פשוט שאפשר על קוברנטס, על היכולות שלו, על מה צריך להתקין בשביל לעבוד איתו והדגמה של העלאה לענן אפליקציה בעזרת קוברנטס. כן נדרש ידע קודם ב Docker ורצוי היכרות עם Node.JS. אם יש לכם V בשתי הקופסאות האלה מוזמנים להירשם למפגש בקישור: https://www.tocode.co.il/workshops/107 נ.ב. הקלטה תעלה כאן לאתר כמה שעות אחרי המפגש אז אם השעה לא מסתדרת לכם אין לחץ תמיד אפשר לראות את השידור החוזר. נתראה בחמישי, ינון

ToCode
1 419
# הדבר שלא עשית אלעד עובד כפרילאנסר כבר שנה. הפרויקט הראשון שלו היה פיתוח חנות דיגיטלית לדוד שלו שמנהל חנות צעצועים. זה לא שהדוד יותר מדי רצה חנות דיגיטלית אבל נו מה לא עושים בשביל משפחה. אחרי זה אחד הלקוחות של הדוד ראה את האתר וביקש גם חנות, וככה במשך שנה יצא שאלעד המשיך לפתח חנויות דיגיטליות מכל מיני סוגים. הוא התחיל עם וורדפרס אבל לאורך השנה למד גם Shopify, Rails ואפילו פיתח כמה כלי אוטומציה שעוזרים לו לתת שירות מהיר יותר ללקוח הבא. היום לאלעד יש כמה עשרות חנויות שהוא מנהל וכשלקוח חדש מצלצל (מה שקורה לעתים קרובות) הוא יודע בדיוק איזה מוצר להציע. אירית התחילה לעבוד כפרילאנסרית בערך באותו זמן של אלעד וגם הפרויקט הראשון שלה היה דרך משפחה. אצלה זאת היתה בת-דודה שבדיוק פתחה גלריה ורצתה אתר כדי למכור את הציורים שלה. בעקבות הבת-דודה הגיעו עוד שתי חברות ציירות אבל הפעם אירית וויתרה על העבודה. היא מצאה פרויקט יותר משתלם אצל מכר שבדיוק גייס כסף לסטארט-אפ חדש שפתח והתחילה לבנות להם אפליקציית Mobile חוצת פלטפורמות. שישה חודשים מאוחר יותר האפליקציה לא ממש התרוממה והסטארט-אפ הלך ל Pivot. אירית פתחה פרופיל ב X-Place והצליחה למצוא עבודה יחסית משתלמת בתור פרילאנסרית המפתחת קוד Backend למוצר שעושה אופטימיזציה לפרסומות. לא מזמן הסטארט-אפ העביר את הפיתוח לאוקראינה ואירית חזרה ל X-Place למצוא את הפרויקט הבא. במהלך השנה אירית הרוויחה משמעותית יותר מאלעד, אולי אפילו כפול. אלעד לעומתה בנה נכס ובשנה הבאה הוא יוכל להעלות מחירים ולגבות ריטיינר מלקוחות קיימים. העסק שלו צומח בזמן שאירית מתחילה כל כמה חודשים שוב מאותה נקודה. כפרילאנסרים, בחירת הפרויקטים היא האחריות הכי גדולה שלנו. תבחרו פרויקטים נכונים ותוכלו לבנות עסק שיחזיק ויתפתח לאורך שנים. התמורה הכספית של פרויקט בודד היא אולי פרמטר שקל למדוד אותו אבל בטווח הרחוק כמעט חסר חשיבות.

ToCode
1 419
# תרגיל אחד מספיק הילד שלי בכיתה ד קיבל שיעורי בית במחשב באנגלית: המחשב מקריא מילה ואז הילד צריך ללחוץ על התמונה של המילה שהוקראה. המטרה כנראה לתרגל אוצר מילים או לאמן את הילד לזהות מילים מקריאה או מה שלא יהיה. אבל בגלל שיש יחסית מעט מילים ברשימה, וההתחלה של כל מילה היא שונה, אז מהר מאוד הוא תפס את הפרנציפ ואיך שהרובוט התחיל רק להקריא את ההברה הראשונה של המילה מיד הילד לוחץ על התמונה המתאימה כדי להתקדם. זה קסום ולא יעיל באותה מידה. לשאלה שלי למה הוא לא מקשיב לכל המילה הוא ענה שהוא היה שמח להקשיב אבל התרגיל חוזר על עצמו כל כך הרבה פעמים שזה חסר טעם ומשעמם. הוא מעדיף לסיים את זה מהר ולהתקדם לדברים שהוא באמת רוצה לעשות. קסום. את האפקט לטווח הרחוק של כאלה תרגילים אפשר לראות בצורת הלימוד הלימוד שלנו כמבוגרים: במקום להחליט שאנחנו מקדישים שעה לתרגול, אנחנו לוקחים רשימת תרגילים ומחליטים שצריך לסיים את כולה, ואז נכנסים למצב עבודה בו אנחנו מנסים לסיים את כל התרגילים כמה שיותר מהר. כאילו אם "סיימתי" רשימה אקראית של תרגילים זה אומר משהו על רמת הידע שלי. במקום לחפש התאמות שוב ושוב היינו יכולים להחליט שאנחנו מתמקדים רק במילה אחת. אנחנו מחפשים שירים (באנגלית) עם המילה הזאת, סיפורים (באנגלית) עם המילה הזאת, מנסים למצוא אותה בסרטים (באנגלית) ביוטיוב, מכינים מדבקות עם המילה הזאת (באנגלית) ומדביקים על חפצים בבית. לימוד חופשי שמתחיל ממילה אחת מוביל לבד לידע נרחב בהרבה מאשר לימוד מבוסס צ'קליסט. אני לא חושב שבתי ספר הולכים להשתנות בתקופה הקרובה. אבל אם כבר סיימתם את הבית ספר ואתם מחפשים ללמוד נושא טכנולוגי חדש, שווה לזכור את הדברים שלא אהבתם בשיטת הלימוד שלהם ולא לחזור עליהם עכשיו. תרגיל אחד מספיק, ועדיף לפתור אותו כמה שיותר לאט.

ToCode
1 419
תבנית מסוכנת אחרונה לרשימה הזאת היא Render Props שגורמת לנו לכתוב קוד שנראה כמו קומפוננטה אבל למעשה הוא לא. הבעיה עם אלה זה שהספריה שמשתמשת ב Render Props תשתול את קטעי הקוד שלנו בתוך קומפוננטות שלה, עליהן אנחנו לא יודעים שום דבר. התוצאה היא שכשאני מסתכל על קוד אני לא יודע להגיד מתי הוא הולך להתרנדר, כלומר איך הוא משפיע על ביצועי המערכת וזרימת המידע בה. מה עושים? בגדול - פחות Hooks, קומפוננטות קטנות יותר ושמשפיעות על עצמן בלבד. לא תמיד זה קל בסיבוב הראשון אבל זה משהו ששווה להתאמץ בשבילו בסבבי Refactoring.

ToCode
1 419
# חמישה דברים שהופכים את קוד ריאקט שלי לקשה להבנה כשריאקט נכנס לאופנה אחד הטיעונים המרכזיים להשתמש בו היה סדר בקוד. המחשבה לפני ריאקט היתה שאנחנו כותבים קוד שמטפל באירועים, לדוגמה "כל פעם שמשתמש לוחץ על כפתור תעשה X" או "כל פעם שמשתמש גולל את המסך תעשה Y". שיטת האירועים הפכה מאוד קשה לתחזוקה כשהקוד התפרס על פני המון קבצים, וכל קובץ הוסיף עוד ועוד אירועים לאותם כפתורים. יותר גרוע היה שהתחלנו לחבר אירועים לדברים שלא באמת קורים על המסך (כל פעם שמשתנה X מתעדכן תזרוק אירוע). ריאקט היה אמור לתקן את הבלאגן הזה במעבר לשיטת עבודה דקלרטיבית. במקום להגיד מה לעשות כשקורה משהו, אנחנו פשוט מגדירים איזה מידע יש במערכת ואיך ה UI נגזר מהמידע, וריאקט משלים את החסר. אם בעקבות לחיצה על כפתור משתנה מסוים מתעדכן, אוטומטית ריאקט ידע לעדכן את ה UI לפי הערך החדש. לכאורה ה UI תמיד יהיה עקבי עם המשתנים שלנו ואם נדפיס תמונה של כל המשתנים במערכת נוכל תמיד לדעת מה יהיה המצב על המסך. זה באמת פתר כל מיני באגים של סינכרון בין מקומות שונים ב UI אבל יצר באגים חדשים ויחודיים לריאקט. הנה 5 תבניות שלדעתי הופכות את קוד ריאקט שאני כותב לקשה מאוד לדיבוג. ## אפקטים המקום הראשון שהממלכה הקסומה של ריאקט נסדקת הוא useEffect. וזה לא (רק) הממשק המסורבל שלו. הבעיה עם useEffect היא שאתה אף פעם לא יודע על מה האפקט הולך להשפיע. בעוד ש State הרבה פעמים תחום לקומפוננטה בתוכה הוא נמצא, עם אפקט קומפוננטה יכולה להשפיע על כל דבר בעולם, ובצורה לא עקבית. דוגמה קלאסית לאפקט היא קריאות רשת: כל פעם שמשתנה State מסוים מתעדכן הקומפוננטה פונה לשרת כדי לקבל מידע חדש ולעדכן בעזרתו משתנה State אחר. בראייה של מערכת אוסף קומפוננטות כאלה יוצרות הרבה קריאות רשת וקשה לעקוב איזה פעולה בדיוק גרמה לאיזו קריאה. במקרה הכללי ככל שיש לי יותר אפקטים בקוד כך יותר קשה לראות איך פעולה מסוימת מביאה לתוצאה מתאימה לה ויותר קשה לדבר בהגיון על הקוד. ## סטייטים רחוקים הסיפור של State בריאקט היה אמור לתת מענה טוב לדינמיות של קומפוננטה. משתמש עושה פעולה, מידע בזיכרון מתעדכן ואז ה UI מצויר מחדש לפי המידע העדכני. כל זה הגיוני בתוך קומפוננטה בודדת. במצבים יותר מורכבים כשיש לי קומפוננטה עם State שמעבירה את ה State לילדים שלה, ואולי גם הם ממשיכים להעביר את הסטייט הלאה לילדים שלהם, אני מגיע לקוד בו משתמש מבצע פעולה במקום אחד והתוצאה היא שינוי על המסך בהרבה מקומות מפוזרים. מצד אחד זה טוב כי כל השינוי מתואם, אבל מצד שני סטייט מרוחק מביא ליותר מדי render-ים בקומפוננטות לא קשורות וכך במקרים מורכבים לבעיות ביצועים, או להפעלה בטעות של אפקטים. ## ספריות ניהול סטייט גלובאלי ספריות ניהול סטייט גלובאלי כמו Redux או MobX היו אמורות לפתור את בעיית הסטייט המרוחק ולתת לי מקום אחד שמנהל את השינוי בסטייט שמשפיע על כל היישום. הבעיה שגם ל MobX וגם ל Redux יש בעיות שלהן (בעיקר בכל מה שקשור לזיהוי שינויים) וכך הן רק עושות יותר נזק מתועלת. במקום לעדכן משתנה State מרוחק אני עכשיו קורא לפונקציה גלובאלית של MobX ואז מנסה להבין למה השינויים לא גרמו ל Render מחדש במקומות המתאימים ואיך לעקוף את האופטימיזציות שהספריות האלה הכניסו. יותר מזה, ספריות ניהול הסטייט ובפרט כל תבנית Flux מעודדות עבודה עם אוביקטי Singleton גדולים (כל Store הוא Singleton Object) ויוצרות קוד שקשה לבדוק אותו כל כי בדיקה משפיעה על המצב הגלובאלי. ## מפתחות הדרישה של ריאקט לציין "מזהה" לכל פריט מידע שמרונדר ברשימה היא הגיונית באפליקציות מסוג מסוים, אבל ככל שהאפליקציות יצירתיות יותר היא עלולה להפוך למעיקה. כשאין מפתחות טבעיים אנחנו מתאמצים "למצוא" דברים שנראים כמו מפתחות ועוברים להשתמש באינדקס של פריט בלולאה או בטקסט של אחד השדות של הפריט. שימוש במפתחות באמת עוזר לייצר חיבור בין מה שרואים על המסך לבין האוביקטים שנשמרים בזיכרון, וקשה להאשים את ריאקט שדורש מאיתנו את זה, אבל באפליקציות Client SIde כשהאוביקטים שנשמרים בזיכרון לא תמיד מכילים מפתח ברור, הדרישה הזאת הופכת את הקוד למסורבל ויותר רגיש לבאגים. במיוחד צריך לשים לב ששינוי במפתח גורם ליצירה מחדש של האלמנט ב DOM, ולכן אם בחרתי מפתח לא נכון אני עלול לאבד פוקוס בתיבת טקסט או לגרום לחלון מודאלי להיעלם ויהיה לי קשה להבין למה. (זה קל כשהבעיה באותה קומפוננטה, הרבה יותר קשה לראות את הבעיות האלה כשהמפתח הלא נכון נמצא 5 קומפוננטות מעליך). ## רנדר פרופס

ToCode
1 419
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="xenodochial-water-9r533" allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" > הפעם התגובה בתיבת החיפוש היא מיידית וגם הדגשת האותיות. הדבר שכן לוקח זמן הוא גלילה מאחר והעברנו את החישוב לאירוע scroll. אבל זה כבר כמעט ולא מורגש.

ToCode
1 419
# טיפ ריאקט: רינדור רשימות ארוכות ריאקט נותן לנו הרגשה שהכל אפשרי. שאם רק ניתן לו לעשות את העבודה שלו נוכל לקבל ביצועים מצוינים ואפליקציה שמשתמשים יהנו ממנה. המציאות לא תמיד תואמת את התחושה. מקום אחד שתמיד מפתיע מתכנתים הוא רשימות ארוכות, והאופן בו ריאקט מטפל (נו, מנסה לטפל) בכל הסיבוך סביב זה. ## מה שבור ברשימות ארוכות הסנדבוקס הבא כולל רשימה ארוכה: <iframe src="https://codesandbox.io/embed/smoosh-violet-5e0lt?fontsize=14&hidenavigation=1&theme=dark" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="smoosh-violet-5e0lt" allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" ></iframe> לטובת מי שאין לו אייפריימים הנה הקוד עצמו:
import "./styles.css";
import { useState } from "react";
import _ from "lodash";

function HilightedWord(props) {
  const { hl, text } = props;

  return Array.from(text).map((ch) =>
    hl.includes(ch) ? <span className="hl">{ch}</span> : <span>{ch}</span>
  );
}

export default function App() {
  const [text, setText] = useState("");
  return (
    <div className="App">
      <div>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
      </div>
      <p>You typed {text}</p>
      <ul>
        {_.range(5000).map((i) => (
          <li key={i}>
            <HilightedWord hl={text} text="Hello world" />
          </li>
        ))}
      </ul>
    </div>
  );
}
יש פה רשימה של 5000 פריטים ותיבת חיפוש מעליהם. כשאנחנו כותבים טקסט בתיבה האותיות מהטקסט שמופיעות בפריטים שברשימה יודגשו בצבע אדום. החלק המרשים לרעה פה הוא כמה זמן לוקח לעמוד להתמודד עם הלחיצה שלי. בואו רק נגיד שיש אנשים שיספיקו לסיים כוס אספרסו עד שיראו את הטקסט מתעדכן בתיבה. זה קורה בגלל שכל שינוי טקסט בתיבה גורם לריאקט ללכת ולהפעיל render על כל ה 5,000 קומפוננטות שברשימה כי אולי חלקן התעדכנו. ואין ממש דרך לצאת מזה: החישוב של מה מתעדכן ומה לא צריך לקרות מתישהו בשביל שהממשק יראה את המידע הנכון. נכון? ## והטיפ להיום- החישוב לא חייב לקרות עכשיו נו, כמעט נכון. כן החישוב צריך לקרות אבל אף אחד לא אמר שהוא צריך לקרות עכשיו. זה נכון שיש 5000 פריטים ברשימה אבל בקושי 50 מהם מוצגים בכל זמן נתון. טריק אחד שאפשר לנסות הוא להפעיל render רק על הפריטים שמשתמש רואה, ולהפעיל את ה render על האחרים רק כשינסו לגלול אותם למסך. זאת בדיוק המטרה של ספריית react-window. הקוד עם הספריה נראה כך:
import React, { useState } from "react";
import { FixedSizeList as List } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";

import "./styles.css";

function HilightedWord(props) {
  const { hl, text } = props;

  return Array.from(text).map((ch) =>
    hl.includes(ch) ? <span className="hl">{ch}</span> : <span>{ch}</span>
  );
}

export default function Example() {
  const [text, setText] = useState("");

  return (
    <>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
      <AutoSizer>
        {({ height, width }) => (
          <List
            className="List"
            height={height}
            itemCount={1000}
            itemSize={35}
            width={width}
          >
            {({ index, style }) => (
              <div style={style}>
                <HilightedWord hl={text} text={`Hello World`} />
              </div>
            )}
          </List>
        )}
      </AutoSizer>
    </>
  );
}
השינוי המרכזי מהקוד שאני כתבתי הוא שהפעם זו react-window שיוצרת את הרשימה ולכן היא גם תהיה אחראית על רינדור הפריטים. התוצאה היא תיקון מאוד פשוט לבעיית הביצועים. אתם מוזמנים לשחק עם הגירסה המתוקנת בקודסנדבוקס כאן: <iframe src="https://codesandbox.io/embed/xenodochial-water-9r533?fontsize=14&hidenavigation=1&theme=dark"