February 26, 2025

ReactJS Essentials Course פנקס כיס

ריאקט - הבסיס

vite

כלי לבניית תכנית ווב בצורה מהירה:

https://vite.dev/

ניתן להשתמש במנגנון ה-template create כדי ליצור פרוייקטי ריאקט בלי מאמץ.
מריץ גם את השרת.

מה זה ריאקט?

זהו פריימווק דקלרטיבי לממשק משתמש.

מה זה קומפוננטה

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

ליצור קומפוננטה

החזרה עם סוגריים מעוגלות שאומר שזה קוד HTML בתוך קוד JS.

1
2
3
4
5
6
7
8
9
10
11
12
function Header() {
return (
<header>
<img src="src/assets/react-core-concepts.png" alt="Stylized atom" />
<h1>React Essentials</h1>
<p>
Fundamental React concepts you will need for almost any app you are
going to build!
</p>
</header>
);
}

אפשר להשתמש בזה באופן הבא:

1
2
3
4
5
6
7
8
9
10
11
12
function App() {
return (
<div>
{Header()}
<Header></Header>
<Header/>
<main>
<h2>Time to get started!</h2>
</main>
</div>
);
}

Build in comps

lowercase
html elements
dom nodes

Custom comps:

uppercase
defined by u - wraps built in
react traverse until it recognizes only built in comps

ערכים דינמיים בקומפוננטה

כדי להוסיף ערכים יש להשתמש ב-{}.

1
2
3
4
5
6
7
8
9
10
return (
<header>
<img src="src/assets/react-core-concepts.png" alt="Stylized atom" />
<h1>React Essentials</h1>
<p>
{"ABCDEFG"} React concepts you will need for almost any app you are
going to build!
</p>
</header>
);

ערכים דינמיים לתכונות HTML

ניתן לעשות import לקבצי css וקבצים אחרים.

1
import reactImg from "./assets/react-core-concepts.png";

העברת מידע בעזרת props

1
2
3
4
5
6
7
8
9
function CoreConcept(props) {
return (
<li>
<img src={props.image} alt={props.title} />
<h3>{props.title}</h3>
<p>{props.description}</p>
</li>
);
}

או בעזרת desctruction ניתן להשתמש באובייקטים ואז לפצל אותם לתכונות:

1
2
3
4
5
6
7
8
9
10
11
function CoreConcept({ image, title, description }) {
return (
<li>
<img src={image} alt={title} />
<h3>{title}</h3>
<p>{description}</p>
</li>
);
}

{CORE_CONCEPTS.map((core) => {return <CoreConcept {...core} />;})}

פיצול קומפוננטה לקובץ

בקובץ אחר נרצה להוסיף export default במידה וזה הדבר היחידי בקובץ:

1
2
3
4
5
6
7
8
9
export default function CoreConcept({ image, title, description }) {
return (
<li>
<img src={image} alt={title} />
<h3>{title}</h3>
<p>{description}</p>
</li>
);
}

ולעדכן imports.

import XXX.css

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

props children

ניתן להעביר ערכים גם בעזרת הילדים:

1
2
3
4
5
6
7
8
9
10
11
function MyComp(props){
return (
<span>{props.children}</span>
);
}

// ....
<MyComp>Hello World</MyComp>

// ... Rendered as
<span>Hello World</span>

השימוש בילדים זה אופציה מהירה יותר ומאפשר אנקפסולציה לקוד JSX.
כמו כן גם מאפשר כתיבה שדומה יותר לקוד HTML.

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

Component listeners

ניתן להעביר פונקציות על מנת להפעיל התנהגות:

1
2
3
4
5
6
7
8
9
10
export default function TabButton({ children, onClick }) {
function click() {
alert("Hello");
}
return (
<li key={1}>
<button onClick={onClick ?? click}>{children}</button>
</li>
);
}

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

1
2
3
4
5
6
7
8
9
10
export default function TabButton({ children }) {
function click(name) {
alert("Hello " + name);
}
return (
<li key={1}>
<button onClick={()=>{click("Bob")}}>{children}</button>
</li>
);
}

מומלץ להחזיר callable לאירוע.

לעדכן את ריאקט שה-UI שלנו השתנה

אם סתם נזרוק משתנה לתוך הקוד, ריאקט לא יידע שהוא ישתנה:

1
2
3
4
5
6
7
let myName = "Shrek":

return (
<div>
Hello <span>{myName}</span>
</div>
);

הקומפוננטה תרוץ רק פעם אחת!

כדי לתקן את זה צריך להשתמש במשהו שנקרא React hook.
מה שנשתמש בו הוא useState

1
import { useState } from "react";

חייבים לקרוא לפונקציה ברמה בגבוה

  1. חייבים להשתמש בזה בתוך קומפוננטה ולא מחוץ.
  2. חייבים לקרוא לזה בהתחלה ולא בתוך תנאי או משהו פנימי
    למשל זה אסור:
1
2
3
4
5
function App(){
if(someCondition){
const [val,setVal] = useState(0);
}
}

עדכון של הUI

1
2
3
4
5
6
7
8
9
10
11
12
13
let myName = "Shrek":
const [selectedTopic, setSelectedTopic] = useState("Please choose an example");

function changeContentOnClick(buttonPressed) {
setSelectedTopic(buttonPressed);
}

return (
<div>
<button onClick={()=>{changeContentOnClick("MyButton")}}>Choose</button>
Hello <span>{selectedTopic}</span>
</div>
);

אם לרנדר או לא לרנדר - תנאים

אפשר לקצר עם ?: או עם &&.

דרך ראשונה - ?:

1
{!selectedTopic ? <p>Please select an example.</p> : null}

דרך שנייה - &&

1
2
3
4
5
6
7
8
9
10
{selectedTopic && (
<div id="tab-content">
<h3>{EXAMPLES[selectedTopic].title}</h3>
<p>{EXAMPLES[selectedTopic].description}</p>
<pre>
<code>{EXAMPLES[selectedTopic].code}</code>
</pre>
</div>
)}

דרך שלישית - if else

1
2
3
4
5
6
7
8
9
10
11
12
let tableContent = <p>Please select a topic</p>;

if(selectedTopic){
tableContent = <div id="tab-content">
<h3>{EXAMPLES[selectedTopic].title}</h3>
<p>{EXAMPLES[selectedTopic].description}</p>
<pre>
<code>{EXAMPLES[selectedTopic].code}</code>
</pre>
</div>;
}

Styling using classes

בתוך JSX אנחנו משתמשים ב-className.

1
<button className={isSelected ? 'active' : undefined}>Click me </button>

ניתן להשתמש בכמה קלאסים

1
<button className="btn btn-primary">Click</button>

Listing

בקצרה השתמשו ב-map כדי ליצור ממערך רשימה של קומפוננטות.

1
2
3
{CORE_CONCEPTS.map((core) => (
<CoreConcept key={core.title} {...core} />
))}

השתמשו ב-key כדי לומר ל-react איך ל

React - Deep dive

ריאקט עובד בתצורת קומפילציה - הוא בונה ומאפטמז את הקוד ומייצר קבצים שניתן להריץ בדפדפן.

להשתמש בפונקציות createElement

האם חייבים JSX?
ניתן גם לייצר אלמנטים בעזרת פונקציות בנויות של ריאקט.

1
2
3
4
5
6
7
8
9
React.createElement(
'div',
{id:'content'},
React.createElement(
'p',
null,
'Hello World'
)
)

==

1
2
3
<div id="content">
<p>Hello World!</p>
</div>

בתצורה של הפונקציות לא צריך באמת לבנות קבצי JSX.

JSX הוא בסופו של דבר תוסף שיש לו תהליך בנייה משלו.
בעזרת קריאה ישירה לפנוקציית ג’אווהסקריפטית אז נמנע מתהליך הבנייה.

Fragments

אלמנטים JSX צריכים שיהיה להם אלמנט שורש:

אסור:

1
2
<Header></Header>
<MyContent></MyContent>

חייבים:

1
2
3
4
<div>
<Header></Header>
<MyContent></MyContent>
</div>

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

במקום שיהיה לנו div נוסף נוכל להשתמש באלמנט Fragment.

1
2
3
4
5
6
7
8
import Fragment from 'react';

function MyComponent(){
return (<Fragment>
<Header></Header>
<MyContent></MyContent>
</Fragment>);
}

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

1
2
3
4
<>
<Header></Header>
<MyContent></MyContent>
</>

פיצול קומפוננטות

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

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

פיצול קומפוננטות ע”פ פיצ’רים או סטייט

יתרונות בפיצול קומפוננטות:

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

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

המאפיין id לא עובר לתוך האלמנט, הרנדרר מתעלם מהמפאיינים האלו.

1
2
<Section id="examples">
</Section>

זה לא עובר לתוך האלמנט section:

1
2
3
4
5
6
7
8
function Section({title,chidlren}){
return (
<section>
<h2>{title}</h2>
{children}
</section>
)
}

כדי להעביר אותם צריך להעביר אותם ידנית:

1
2
<Section id="examples">
</Section>

זה לא עובר לתוך האלמנט section:

1
2
3
4
5
6
7
8
function Section({title,id, chidlren}){
return (
<section id={id}>
<h2>{title}</h2>
{children}
</section>
)
}

Forwarding props

בעזרת פיצ’ר של ג’אווה סקריפט שנקרא Rest Properties נוכל להעביר כל מיני פרמטרים ישירות בקלות.
ואז נצטרך לבצע Deconstruction על האלמנט:

1
2
3
4
5
6
7
8
function Section({title,chidlren, ...props}){
return (
<section id={id} {...props}>
<h2>{title}</h2>
{children}
</section>
)
}

Using JSX Slots - Multiple slots

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<Card
header={<h1>title</h1>}
content={<p>Content</p>}
footer={<a href="#">Read more</a>}
/>

function Card({header, content, footer}){
return (<>
<nav>
{header}
</nav>
<section>
{content}
</section>
<footer>
{footer}
</footer>
</>);
}

בניית קומפוננטות דינמיות על ידי העברת הטייפ

ניתן להעביר את הטייפ של קומפוננטה או אלמנט על מנת ליצור קומפוננטה חדשה ממנה

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function MyTitle({chidlren}){
return (<h1>{chidlren}</h1>);
}

export default function RedTitle({ titleType, children }) {
const TitleType = titleType;
return <TitleType style={{ color: "red" }}>{children}</TitleType>;
}

// Usage
<RedTitle titleType={MyTitle}>{big}</RedTitle>
<RedTitle titleType={"h2"}>{middle}</RedTitle>
<RedTitle titleType={"h3"}>{smaller}</RedTitle>

יצירת דיפולטים למאפייני קומפוננטה

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

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

1
2
3
4
5
6
export default function RedTitle({ titleType = "h1", children }) {
const TitleType = titleType;
return <TitleType style={{ color: "red" }}>{children}</TitleType>;
}
<RedTitle>{middle}</RedTitle>

קומפוננטות הן עצמאיות

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

1
2
<RedTitle>One</RedTitle>
<RedTitle>Two</RedTitle>

שינוי סטייט על פי הסטייט הקודם

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

כן:

1
setIsEditing(wasEditing => !wasEditing);

לא:

1
setIsEditing(!isEditing);

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

העתקת אובייקט עדיפה על שינוי הסטייט

כן:

1
2
const updateUser = {...user};
updaeUser.name = "New Name";

לא:

1
2
const updateUser = {user};
updaeUser.name = "New Name";

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

העלאת סטייט לקומפוננטה העליונה

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function FirstComp({setName}){
return (<button onClick={e=> setName("Bob")}></button>);
}

function SecondComp({name}){
return (<label>{name}</label>);
}

function App(){
const [name,setName] = userState("");

return (
<FirstComp setName={setName}></FirstComp>
<SecondComp name={name}></SecondComp>
)
}

שימוש בסטייט יחיד

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

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

1
2
const [player, setPlayer] = useState(); // Who
const [board, setBoard] = useState(); // Where
1
const [turns, setTurns] = useState(); // Who and Where

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

Event sourcing Pattern

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

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

סטיילינג של קומפוננטות ב-CSS

  1. CSS גלובלי (.css + className)

יתרונות

הכי פשוט ומהיר להתחלה.

קבצים קטנים, בלי תלות בספריות.

עובד מעולה עם כל בנדלר/SSG.

חסרונות

סיכוי ל־name collisions ולדליפות סגנון.

קושי בניקוי ועקיבות בפרויקטים גדולים.

theming והרכבה מותנית בכללים ידניים.

  1. CSS Modules

יתרונות

בידוד שמות אוטומטי (scoped).

DX טובה בלי ריצה בזמן אמת.

תמיכה נוחה ב-TypeScript להשלמת שמות מחלקות.

חסרונות

קשה לשתף לוגיקה דינמית (מצבים/var-ים) בלי מחלקות נוספות.

theming מורכב יותר (לרוב עם CSS Variables).

  1. Sass/SCSS (עם גלובלי או Modules)

יתרונות

משתנים, mixins ו-nesting משפרים ארגון ו-DRY.

קומפייל לפרונט — ללא עלות ריצה.

חסרונות

עוד שכבת כלים/בניית קובץ.

משתני Sass הם סטטיים בזמן build (לא דינמיים בזמן ריצה).

  1. Inline Styles (style={{ ... }})

יתרונות

הצמדה ישירה ללוגיקה; קל לתנאים ודינמיות.

אין התנגשות שמות.

חסרונות

אין pseudo-selectors/מדיות/animations (אלא אם JS).

ביצועים פחות טובים ברינדור חוזר של אובייקטים.

קוד פחות קריא בעיצובים גדולים.

  1. CSS-in-JS בזמן ריצה (styled-components / Emotion)

יתרונות

סגנון צמוד לקומפוננטה, תחזוקה נוחה.

theming מצוין (ThemeProvider), props דינמיים.

אפשרויות קומפוזיציה חזקות.

חסרונות

עלות ריצה (runtime) והזרקת <style> דינמית.

SSR דורש הגדרה (ServerStyleSheet/extractCritical).

לפעמים איטרציה איטית בקנה מידה גדול.

  1. CSS-in-JS ללא ריצה (vanilla-extract, Linaria, compiled)

יתרונות

מייצר CSS בזמן build — אפס עלות ריצה.

עדיין כותבים “כמו JS/TS” עם טיפוסיות וכללים מודולריים.

טוב ל-SSR וביצועים.

חסרונות

פחות דינמיות בזמן ריצה לעומת runtime CSS-in-JS.

עקומת לימוד קלה לכלי/קונפיגורציה.

  1. Utility-First (Tailwind CSS)

יתרונות

פיתוח מהיר מאוד, אין “קפיצה” בין קובצי CSS ו-JSX.

Purge/treeshake חזק → CSS קטן בפרודקשן.

עיצוב עקבי באמצעות design tokens וקונפיגורציה אחת.

חסרונות

JSX “עמוס” בקלאסים; דורש הטמעה של naming mindset.

התאמות מיוחדות (מצבים מורכבים/animations) לפעמים פחות אינטואיטיביות.

תלות במסגרת חיצונית.

  1. System Props / sx (MUI/Chakra)

יתרונות

API דקלרטיבי ל-spacing/typography/layout.

theming עמוק “מהקופסה”.

מהיר ל-CRUD UI ולמערכות עיצוב.

חסרונות

תלות בספריית UI כבדה יחסית.

לעתים קוד JSX מרובה props לעיצוב.

  1. CSS Variables (Design Tokens)

יתרונות

theming בזמן ריצה (כולל dark mode) בלי JS כבד.

עובד עם כל שיטה לעיל (גלובלי/Modules/Tailwind).

משתלב נהדר עם SSR ו-static.

חסרונות

צריך ארגון טוב של tokens ושכבות (root/scope).

לוגיקה מתקדמת עדיין ב-JS (toggle/contexts).

מתי לבחור מה (כללי אצבע)

פרויקט קטן/בלוג/דוקו: CSS Modules או גלובלי + קצת Variables.

אפליקציה גדולה עם הרבה מצבים ותמות: CSS-in-JS (Emotion/styled) או Zero-runtime (vanilla-extract) + Tokens.

פיתוח מהיר של UI עקבי: Tailwind או System Props (MUI/Chakra).

ביצועים/SSR קפדניים: Zero-runtime או CSS Modules + CSS Variables ל-theming.

Strict Mode

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

1
2
3
4

<StrictMode>
<App/>
</StrictMode>

עוד:
https://react.dev/reference/react/StrictMode

Refs

מאפשר לעבוד עם האלמנט דום של העמוד.

  • גישה לאלמנטים עם סטייט
  • מאפשר להוציא פונקציות מחוץ לקומפוננטה
1
2
3
const inputName = useRef();

<input ref={inputName} type="text" />

ניגש לערך ע”י קריאה:

1
inputName.current.value

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

1
2
3
4
5
<h2>Welcome {inputName.current ? inputName.current.value : "unknown entity"}</h2>
<p>
<input ref={inputName} type="text" />
<button onClick={handleClick}>Set Name</button>
</p>

State vs Refs

סטייט

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

Refs

לא יוצר עדכונים לגרפיקה.
ערך ישיר לאלמנט דום.

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

כמו כן ניתן להעביר אותם גם לקומפוננטות אחרות:

1
2
3
4
5
6
7
const dialogRef = useRef();
<ResultModal ref={dialogRef} result={"lost"} targetTime={targetTime} />

export default function ResultModal({ ref, result, targetTime}) {
return <dialog ref={ref} className="result-modal">
</dialog >;
}

Forward refs

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

1
2
3
const FancyButton = React.forwardRef((props, ref) => (  <button ref={ref} className="FancyButton">    {props.children}
</button>
));

useImperativeHandle

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

1
2
3
4
5
6
7
8
9
10
export default function ResultModal({ ref, result, targetTime }) {
const dialogRef = useRef();
useImperativeHandle(ref, () => ({
open: () => {
dialogRef.current.showModal();
}
}));
return <dialog ref={dialogRef} className="result-modal">
</dialog>;
}

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

קריאה:

1
ref.current.open();

Portals

פורטלים מאפשר להזיז אלמנט לאלמנט אחר בדום.
במודאלים ודיאלוגים זה מושלם כי אנחנו יכולים ליצור אותם תחת אלמנט בודד ב-body ולא באמצע ה-dom.

https://react.dev/reference/react-dom/createPortal

למשל יצירה של אלמנט ב-body:

1
2
3
4
5
6
7
8
9
10
11
import { createPortal } from 'react-dom';

// ...

<div>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body
)}
</div>

ניהול סטייט מורכב יותר - העברת פרופ - Prop Drilling

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

App

  • Header
    • CartModal
      • Cart - Display Cart
  • Shop - Update Cart
    • Product - Update Cart

קומפוזיציית קומפוננטות

דרך אחת לפתור את הבעיה זה לעלות את הקומפוננטות רמה אחת למעלה
למשל אם הקומפוננטה Product מרונדרת תחת Shop,
נוכל להעביר את הקומפוננטות של Product כ-children המרונדרים ב-App במקום ב-Shop.

App -

  • Shop
  • Children - Product - has Update cart
1
2
3
4
5
6
7
<Shop>
{DUMMY_PRODUCTS.map((product) => (
<li key={product.id}>
<Product {...product} onAddToCart={handleAddItemToCart} />
</li>
))}{" "}
</Shop>

ב-Shop:

1
<ul id="products">{children}</ul>

React Context API

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

ניצור קונטקס חדש, בדרך כלל נשמור בתיקייה אחרת כגון store:

1
2
3
4
5
import { createContext } from "react";

export const CartContext = createContext({
items:[]
});

כדי להשתמש בו:

1
2
3
4
5
import CartContext from './store/shopping-cart-context.jsx'

<CartContext.Provider>
..... Put things here
</CartContext.Provider>

בקומפוננטות אחרות ניתן לעשות:

1
2
3
4
5
6
7
8
import {use, useContext} from 'react';

import {CartContext} from "../store/shopping-cart-context.jsx"

export default function Cart({ items, onUpdateItemQuantity }) {
const cartCtx = useContext(CartContext);
// or const cartCtx = use(CartContext);
}

ההבדל ש-use הוא גמיש יותר כמו להשתמש בו בתוך תנאי.
כמו כן ה-use הוא בריאקט חדש יותר.

Context.Consumer

השתמשנו ב-Provider, אז אפשר גם לעשות Consume בעזרת התגים:

1
2
3
4
5
6
7
8
<CartContext.Consumer>
{(cartCtx) => {
// Code goes here
return <div>
{cartCtx.items}
</div>;
}}
<CartContext.Consumer>

Context Value השתנה

כשה-Value השתנה ריאקט מעדכן את הקומפוננטה לבד אם

Context separate components

מאוד נוח להוציא את הקונטקס לקומפוננטה משל עצמה

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { createContext } from "react";
import { useState } from "react";
import { DUMMY_PRODUCTS } from "../dummy-products.js";

export const CartContext = createContext({
items: [],
addItemToCart: () => {},
updateItemQuantity: () => {},
});

export default function CartContextProvider({children}) {
const [shoppingCart, setShoppingCart] = useState({
items: [],
});

const ctxValue = {
items: shoppingCart.items,
addItemToCart: ()=>{},
updateItemQuantity: ()=>{},
};

return <CartContext.Provider value={ctxValue}>
{children}
</CartContext.Provider>;
}

// ...

<CartContextProvider>
<Header/>
<Cart/>
</CartContextProvider>

Use Reducer

הפונקציה מגדירה מעיין סטייט נוסף אולם הוא עובד ע”פ עקרון האיננוטים.
הוא יוצר סטייט ופונקצ’ דיספטצ’.

הפונקציה הזו “זורקת” איוונטים

שלב ראשון נגדיר את ה-Reducer שלנו:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function shoppingCartReducer(state, action) {
if(action.type === "ADD"){
return {
...state,
items: [...state.items, 1] // Added 1
};
}
if(action.type === "ADD"){
let updatedItems = state.items;
updateItems[action.payload.index] = action.payload.value;
return {
...state,
items: [...state.items, 1] // Added 1
};
}
}

שלב שני נגדיר את הסטייט בעזרת useReducer.
הפרמטר הראשון זה ה-Reducer והשני זה סטייט ראשוני.

1
2
3
4
5
6
const [shoppingCartState, shoppingCartDispatch] = useReducer(
shoppingCartReducer,
{
items: [],
}
);

שלב שלישי עושים דיספטצ’:

1
2
3
4
5
6
function handleAddItemToCart(id) {
shoppingCartDispatch({
type: "ADD_ITEM",
payload: id,
});
}

Reducer and Redux

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

על הפוסט

הפוסט נכתב על ידי Ilya, רישיון על ידי CC BY-NC-ND 4.0.

שתפו את הפוסט

Email Facebook Linkedin Print

קנו לי קפה

#Software#ReactJS#References