מבוא לריאקט ו-CSS

משך זמן קריאה: 13 דקות

אמ:לק

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


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

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

 

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

 

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

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

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

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

 

ריאקט ו-CSS

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

CSS in JS

תכלס אין לי הרבה מה לכתוב על זה חוץ מאימוג'י מקיא (ויסלחו לי אלו שכן מחבבים את השיטה). אני ממש ממש לא מתחברת לשיטה הזאת, לא אוהבת את הסמנטיקה שלה, יש לה הרבה בעיות בדיבאגינג וגם אי אפשר להשתמש בכל המאפיינים של CSS (כמו אנימציות למשל, ואם כן זה מצריך שימוש בעוד ספריות משנה כמו למשל Radium).
אני כן אציין שיש יתרונות בשיטה הזאת, ולטובת מי שכן מעניין אותו מזמינה אותו.ה לשמוע את ההרצאה של Christopher "vejeux" Chedeau על היתרונות ואיפה כן כדאי להשתמש בשיטה.

CSS אחד מרכזי

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

CSS Modules

CSS Modules הם חלק מ web-pack, והקסם שלהם הוא שהם מאפשרים לכל קובץ CSS או SCSS להיות שייך אך ורק לקומפוננטה אחת. אף קומפוננטה לא תשפיע עליו והוא לא ישפיע על קומפוננטות אחרות.
להרחבת הידע על CSS/SCSS, ריאקט ו-CSS Modules מצורפת רשימת קריאה:

 

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

ואם זה לא היה מספיק, אז בנוסף לכל השינויים, עברתי מ P.C ל-Mac. למה? כי עברנו כולנו בעבודה למחשבים אישיים, ואני החלטתי להגשים חלום נושן לעבוד על Mac. שורה תחתונה – מרוצה ממש. הדרך הייתה לא קלה, במיוחד שעם המעבר ל-Mac החלטתי לזנוח את הסמארט-גיט שהשתמשתי בו (אחת ההחלטות שאני מברכת עליהן ממש). לא, לא עברתי לעבוד עדיין בפקודות במסך השחור (=הטרמינל, אם כי אני שומרת לי במועדפים את הלינק הזה לפקודות נפוצות לגיט ששמרתי לי מתוך אחד הפוסטים של ליקוטי שיבולים) אבל עברתי לעבוד עם גיט דרך הכלים שיש ב Php-Storm ואני מרוצה ממש!

 

פינת העבודה שלי
פינת העבודה שלי בבית

 

אז איך זה עובד?

בעיקרון כל קומפוננטה מכילה קבצים של JS (בדר"כ אחד) וגם קבצים של JSX, שניים או יותר – תלוי במורכבות של הקומפוננטה, וכן קובץ SCSS אחד אותו אנחנו מייבאים אל קובץ ה-JSX.
מה שמיוחד ב CSS Modules הוא השיוך הבלעדי של הקובץ SCSS אל הקומפוננטה. הקסם הזה נעשה בצורה קצת מבאסת, שמאריכה את השמות של הקלאסים אבל באמת מייחדת את השמות שלהם.

אני אדגים כדי שיהיה ברור:
לכל קומפוננטה יש קובץ SCSS, לדוגמה: my-component.module.scss. מה ש-CSS Modules עושה זה לוקח את שם הקופוננטה ומשרשר אליה כל קלאס שמופיע בקומפוננטה. אם יש לי את הקלאס title אז הקלאס שיתקבל בדפדפן יהיה: my-component_title, ולקינוח – בסוף השם של הקלאס מתווספת סיומת ראנדומאלית של אוסף אותיות ומספרים כך שהקלאס בעצם ייראה ככה: my-component_title_25tj85.

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

אז אנחנו יודעים מה המבנה של הקלאסים, עכשיו איך לעזאזל מכניסים אותם?
בריאקט אנחנו לא עובדים עם קבצי HTML או PHTML, אלא עם קבצי JSX שזה קצת כמו PHTML, מין הכלאה של JS ו-HTML. אנחנו בפרויקט שלנו משתמשים ב TypeScript ולכן הקבצים שלנו הם אינם JS אלא TS, ובמקום JSX יש קבצי TSX (אותו דבר רק במקום JS ו HTML יש לנו TypeScript ו-HTML 🙂 )
עכשיו כבר לא כותבים כמו שהייתי רגילה קודם: class="class-name" אלא בשימוש עם className (אנחנו בתוך קובץ JS, זוכרים?)

<List className={style.list}>

מה כל התוספות האלה אומרות בעצם?

className – מה כבר יש להוסיף – זאת הקריאה לקלאס שלנו 🙂

style – כאשר אנחנו כותבים לפני שם הקלאס שלנו את המילה style אנחנו אומרים לאלמנט שלנו שהקלאס שלו נמצא בתוך קובץ ה SCSS של הקומפוננטה שלנו (אותה ייבאנו בתחילת קובץ ה TSX).
ואם תשאלו מישהו שחבר ממש של JS הוא יגיד לכם שאנחנו קוראים לקלאס במקום list בתוך style. לא הבנתם – לא ממש משנה, גמני לא 🙂

וככה נראה אותו בHTML שלנו כשנכנס דרך ה dev-tools:

<li class="list_list__2YW49">

אם נכתוב את הקלאס שלנו בלי style לפני השם שלו, הקלאס יודפס ב HTML, אבל לא ייקח את העיצוב שלו מתוך קובץ ה SCSS של הקומפוננטה.

<List className={'list'}>

וב-dev-tools? הוא לא יהיה משורשר לקומפוננטה היות והוא נחשב לקלאס גלובאלי:

<li class="list">

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

כמו למשל:

.desktop-only {
  @include media-query('phone') {
    display: none !important;
  }
}

//in TSX file:
<List className={'desktop-only'}>

על איך ולמה קבצים גלובליים – בפוסט המשך 🙂

 

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

<ListItem className={style['list-item']}>

*אפשר עם גרש אחד בתוך הסוגריים המרובעים ואפשר גרשיים. אני אישית מעדיפה בודד.

 

זוכרים שאמרתי שמייבאים את קובץ ה-SCSS שלנו לקומפוננטה? אז שימו לב – אם ייבאנו אותו בצורה הזאת:

import style from '../../styles/packages/list/list.module.scss';

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

import styles from '../../styles/packages/list/list.module.scss';

<ListItem className={styles['list-item']}>

למה זה חשוב לציין את זה – כי קרה לי שה import היה על styles והקלאסים לא, וה-Php-Storm צעק עלי ולא הבנתי למה. אז בגלל זה!

 

מה עושים אם יש לנו יותר מקלאס אחד?!

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

אז כדי לתת לאלמנט יותר מקלאס אחד יש כמה אופציות:

//option #1
className= {[style[`is-open`],style[`nav_item`]].join(" ")}

//option #2
className={`${styles["search-results-item"]} ${styles["selected"]}`}

בשתי האפשרויות יש לנו בעצם מערך של קלאסים, בראשון 2 קלאסים שבאים אחד אחרי השני ואנחנו מחברים אותם עם רווח ביניהם, והשני זה מערך של קלאסים שבסוף באים כרשימה. אבל תכלס, 2 השיטות האלה לא הכי כיפיות ואיזה נחמד שלאנס, שהוא מנהל הצוות של הפרויקט (ולשמחתי הרבה גם אפילו חבר של CSS ועבדתי מולו הרבה בהקמה של קומפוננטות התבנית – עליהם ארחיב בפוסט נפרד), הכניס לנו את הספרייה של classNames שמאפשרת לנו לתת רשימה של קלאסים בלי להוסיף להם את ה-join בסוף או לעטוף כל אחד מהם עם $ וסוגריים מסולסלות.

import classNames from "classnames";
<ListItem className={classNames(styles['list-item'], style['selected'], 'desktop-only'}>

 

שמות ושורות

בניגוד לפרויקט הקודם שעבדתי עליו (ובעצם כל פרויקט שעבדתי עליו גם בעבודה הקודמת שלי), עכשיו קבצי ה-SCSS הם לא נחלתי האישית. כן, לי יש את ה-say האחרון, אבל היות וכל אחד עובד על קומפוננטה, כל אחד יכול לכתוב את ה-SCSS שלה.
העובדה הזאת, שעדיין קשה לי לעיכול – כי אני לא אוהבת שנוגעים לי בקבצים שהיו נחלתי הבלעדית די הרבה זמן (טוב, לא רק שלי, גם של שכטר 🙂 ) הובילו אותי לשנות גישה בנוגע לכתיבה של קוד בשורה אחת (שכטר, לסגור אוזניים ולדלג לפסקה הבאה…). אחרי שנתיים של כתיבת מאפיינים בשורה אחת אני חוזרת לשבור שורות.
ולמה? כי לרוב האנשים זה פחות נוח. גם לי לקח זמן להתרגל לעניין. אני לא ארחיב למה דווקא כן כדאי – מי שרוצה מוזמן לקרוא פה. אבל עכשיו, כשכל המתכנתים בעצם נכנסים לערוך קבצי SCSS, לרובם המכריע נוח יותר כשהסטייל לא יושב בשורה אחת. סיבה שניה, שהיא תכלס הכריעה את הכף, היא קונפליקטים. כאשר יש מאפיין בודד בשורה, קל יותר לפתור את הקונפליקט. נכון, גם ה-JS לא כתוב בשורות נפרדות ועדיין מצליחים לפתור קונפליקטים, אבל למי שפחות מתמצא ב-CSS וצריך לפתור את הקונפליקט, יהיה קל יותר אם הקוד יהיה כתוב בשורות נפרדות.

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

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

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

//the element
.list{
  display: flex; 
  flex-direction: column;

 // list variation:
  &--horizontal{
    flex-direction: row;
  }

//list child element
  &__item{
    margin-top: 6px;
  }

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

<li class="list_list_1kZYS list_list--horizontal__1kZYS footer_list__330jC">

 

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

//HTML:
<div class="popup">
  <div class="popup-header">
    <H2 class="popup-header-title">popup-header</H2>
  </div>
  <div class="popup-footer"></div>
</div>


//SCSS
.popup{
  &-header{
    some style
    &-title{some style}
    }
  &-footer{some style}
}

//SCSS - css Modules compiles to:
<div class="popup_popup__3gwri">
  <div class="popup_popup-heade__3gwri">
    <H2 class="popup_popup-header-title__3gwri">popup-header</H2>
    </div>
    ....
</div>

עכשיו שימוש בשרשור כזה היה מאריך ממש את שם הקלאס, בגלל שכל אחד מהם היה מקבל את שם המודול בהתחלה ואת המספר בסוף. העומס המילולי הזה הביא אותי לצמצום של מלל ולבחירה של שמות מאוד ספציפיים ומאוד פשוטים לכל אלמנט. כך למשל, אם ניקח את דוגמת ה-popup שלנו, נמנעתי מלהשתמש שוב במילה popup בכל קלאס, כי אני אקבל אותו ממילא בגלל השירשור של ה-Css-Modules, והסתפקתי ב-header, title, ו-footer. לא משנה אם יש לי footer בקומפוננטות אחרות, היות וכל אחת מהקומפוננטות עומדת בפני עצמה. הוריי CSS Modules!

//SCSS - CSS Modules with short manes: 
<div class="popup_popup__3gwri"> 
  <div class="popup_header__3gwri"> 
  <H2 class="popup_title__3gwri">popup-header</H2>
  </div>
  .... 
</div>

ואם כבר מריעים ל-CSS Modules אז לידיעת הקוראים, אם נתנו קלאס ב TSX אבל לא הכנסנו לו עיצוב בקובץ SCSS אז הקלאס לא ייכתב ב HTML הסופי. נחמד ממש!

 

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

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *