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

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

איך להפוך Class Component ל Function Component ב React

24/01/2020

למרות שאין בעיה להמשיך לעבוד עם Class Components, קורה לפעמים שנמצא דוגמא ברשת של Class Component ונעדיף להפוך אותה ל Function Component לפני שמשלבים אותה ביישום שלנו.

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

https://github.com/josdejong/jsoneditor/tree/develop/examples/react_demo

והקובץ המרכזי ממנה הוא הפקד הבא:

import React, {Component} from 'react';

import JSONEditor from 'jsoneditor';
import 'jsoneditor/dist/jsoneditor.css';

import './JSONEditorDemo.css';

export default class JSONEditorDemo extends Component {
  componentDidMount () {
    const options = {
      mode: 'tree',
      onChangeJSON: this.props.onChangeJSON
    };

    this.jsoneditor = new JSONEditor(this.container, options);
    this.jsoneditor.set(this.props.json);
  }

  componentWillUnmount () {
    if (this.jsoneditor) {
      this.jsoneditor.destroy();
    }
  }

  componentDidUpdate() {
    this.jsoneditor.update(this.props.json);
  }

  render() {
    return (
        <div className="jsoneditor-react-container" ref={elem => this.container = elem} />
    );
  }
}

הפקד כולל לא מעט פונקציות מחזור חיים ולכן אני חושב שיהיה מעניין להפוך אותו ל Functional Component ולראות בדרך כמה תבניות של React Hooks.

המשך קריאה

בואו נכתוב משחק זיכרון ב React עם useReducer

18/01/2020

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

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

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

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

const initialState = {
  visibleCards: new Set(),
  currentTurn: new Set()
};

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

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

const reducer = produce((state, { type, payload }) => {
  const { cards } = payload;
  if (state.currentTurn.size === 2) {
    startNewTurn(state, cards);
  }

  if (type === "click") {
    const { idx } = payload;
    if (!state.currentTurn.has(idx) && !state.visibleCards.has(idx)) {
      state.currentTurn.add(payload.idx);
    }
  }
});

function startNewTurn(state, cards) {
  const turnCards = Array.from(state.currentTurn);
  if (turnCards.every(c => cards[c] === cards[turnCards[0]])) {
    state.visibleCards = new Set([...state.visibleCards, ...state.currentTurn]);
  }
  state.currentTurn = new Set();
}

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

function MemoryGame(props) {
  const { cards } = props;
  const [state, dispatch] = useReducer(reducer, initialState);

  function cardClasses(state, idx) {
    let res = "card";
    if (state.visibleCards.has(idx) || state.currentTurn.has(idx)) {
      res += " visible";
    }
    return res;
  }

  return (
    <div className="game">
      <ul>
        {cards.map((val, idx) => (
          <li
            className={cardClasses(state, idx)}
            onClick={() => dispatch({ type: "click", payload: { idx, cards } })}
          >
            {val}
          </li>
        ))}
      </ul>
    </div>
  );
}

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

https://codesandbox.io/s/billowing-river-tbmzu

חדש באתר: קורס ריאקט לייב - לומדים חודשיים עם מרצה ויוצאים עם פרויקט ביד

08/01/2020

הי חברים,

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

אני יכול לראות את השיעור כמה פעמים שאני צריך עד שאני מבין.

אני יכול לדלג על קטעים שלא מעניינים אותי.

אני יכול להתאמן בלי שאף אחד מסתכל.

ואני יכול לשאול שאלות בלי להרגיש שרק אני לא הבנתי.

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

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

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

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

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

לכל הפרטים על קורס ריאקט הקרוב מוזמנים לקפוץ לדף הנחיתה החדש שבניתי בקישור https://www.tocode.co.il/bundles/react

נתראה בקורס ינון

קוד סטארטר לפיתוח Dashboard ב React

25/12/2019

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

המשך קריאה

חדש באתר: קורס ריאקט

22/12/2019

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

אבל לפני הכל ולממהרים - זה הלינק לקורס: https://www.tocode.co.il/bundles/react

המשך קריאה

ביי ביי Redux Thunk

21/12/2019

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

המשך קריאה

שלד לפיתוח יישום Chat עם React ו Firebase

18/12/2019

אחד השילובים שאני יותר אוהב בפיתוח הוא Redux ו Web Sockets. זה עובד ממש פשוט ויפה יחד: כל פעם שמגיע אירוע מבחוץ דרך ה Web Socket, יהיה לנו מידלוור שיתרגם את האירוע לאוביקט Redux Action, האוביקט ייכנס למערכת דרך ה Reducers ובאופן אוטומטי המסך יתעדכן כי ריאקט יזהה את השינוי וימשוך את המידע החדש.

בואו נכתוב שלד קצר להמחיש את הרעיון באמצעות שרת Firebase.

המשך קריאה

מבוא זריז ל Redux

07/12/2019

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

(וכן - ניסיתי את MobX, לא נפלתי מהכסא, ואני נשאר עם רידאקס). מוכנים? נמשיך לקוד.

המשך קריאה

חידת ריאקט: דברים שאי אפשר לעשות עם Custom Hooks

28/11/2019

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

שימו לב לקוד הבא שמגדיר Custom Hook כדי ליצור באופן אוטומטי אלמנט Input יחד עם שדה בסטייט שמתאים לו:

function useTextField() {
  const [value, setValue] = useState('');

  function Input(props) {
    return <input type="text" value={value} onChange={(e) => setValue(e.target.value)} />
  }

  return [Input, value, setValue];
}

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

והחידה של היום - מה קורה בתיבה שלא אמור היה לקרות? איפה הבאג בקוד שגורם לבעיה? ואיך בכל זאת הייתם כותבים את הקוד הזה בצורה שעובדת?

יודעים את התשובה? מוזמנים לכתוב הסבר בתגובות.

איך לשמור מערך בסטייט של React Component

15/11/2019

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

המשך קריאה