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

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

על הפוסט

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

שתפו את הפוסט

Email Facebook Linkedin Print

קנו לי קפה

#Software#ReactJS#References