state כ-תמונת מצב
משתני מצב להיראות כמו משתני JavaScript רגילים. עם זאת, הstate מתנת יותר כמו תמונת מצב. הגדר את זה לא משנה את השינוי הstate יש לך, אלא מפעילה עיבוד מחדש.
You will learn
- איך הגדרת מצב מפעילה עיבוד מחדש
- מתי וכיצד עדכוני הstate *למה הstate לא מתעדכנת מיד לאחר הגדרתו
- איך רופא אירועים ניגשים ל”תמונה מצב” של הstate
הגדרת מצב מפעילים מעבד
אתה עשוי לחשוב על ממשק המשתמש שלך כדי לקבוע את התגובה לאירוע משתמש כמו קליק. ב-React, זה עובד קצת אחרת מהמודל המנטלי הזה. בעמוד הקודם, ראית ש הגדרה מצב מבקשת עיבוד מחדש מ-React. זה שכדי שממשק יגיב לאירוע, צריך לעדכן את הstate.
בדוגמה זו, כאשר אתה לוחץ על “שלח”, setIsSent(true) אומר ל-React לעבד מחדש את ממשק המשתמש:
import { useState } from 'react'; export default function Form() { const [isSent, setIsSent] = useState(false); const [message, setMessage] = useState('Hi!'); if (isSent) { return <h1>Your message is on its way!</h1> } return ( <form onSubmit={(e) => { e.preventDefault(); setIsSent(true); sendMessage(message); }}> <textarea placeholder="Message" value={message} onChange={e => setMessage(e.target.value)} /> <button type="submit">Send</button> </form> ); } function sendMessage(message) { // ... }
זה מה שקורה כשאתה לוחץ על הכפתור:
- המטפל באירוע ‘onSubmit’ מבצע.
setIsSent(true)מגדיר אתisSentל-trueומעמיד בתור עיבוד חדש.- React מעבד מחדש את הרכיב לערך ‘isSent’ החדש.
בואו נסתכל מקרוב על הקשר בין מצב לעיבוד.
העיבוד מצלם תמונת מצב בזמן
“עיבוד” פירושו ש-React קורא לרכיב שלך, שהוא פונקציה. ה-JSX שאתה מחזיר מהפונקציה הזו הוא כמו תמונת מצב של ממשק המשתמש בזמן. הprops, רופאי המומחים והמשתנים המקומיים חושבים כולם באמצעות מצבו בזמן העיבוד.
שלא כמו תמונה או פריים של סרט, “תמונה הstate” של ממשק המשתמש שאתה מחזיר הוא אינטראקטיבי. זה כולל לוגיקה כמו מטפלי אירועים שמציינים מה קורה בתגובה לקלט. React מעדכנת את המסך כך שיתאים לתמונה מצב זו ומחברת את המטפלים. כתוצאה מכך, לחיצה על כפתור תפעיל את הרופא הקליקים מה-JSX שלך.
כאשר React מעבד מחדש רכיב:
- React קורא לפונקציה שלך שוב.
- הפונקציה שלך מחזירה תמונת מצב חדשה של JSX.
- React מעדכן את המסך כך שיתאים לתמונה הstate שהפונקציה שלך החזירה.

React executing the function 
Calculating the snapshot 
Updating the DOM tree
Illustrated by Rachel Lee Nabors
זיכרון של משתנה רכיב, מצב אינו כמו רגיל דיווחים לאחר החזרה של הפונקציה שלך. הstate למעשה “חיה” ב-React עצמה - כאילו על הדף! - מחוץ לתפקידך. כאשר React קורא לרכיב שלך, הוא נותן לך תמונת מצב של העיבוד המסוים הזה. הרכיב שלך מחזיר מצב של ממשק משתמש עם קבוצה חדשה של props ומטפל אירועים ב-JSX שלו, כולם מחושבים באמצעות ערכי הstate מהעיבוד הזה!

You tell React to update the state 
React updates the state value 
React passes a snapshot of the state value into the component
Illustrated by Rachel Lee Nabors
הנה ניסוי קטן כדי להראות לך איך זה עובד. בדוגמה זו, אתה עשוי למצוא שלחיצה על כור “+3” תגדיל את המונה שלוש פעמים שהוא קורא ל’setNumber(מספר + 1)’ שלוש פעמים.
ראה מה קורה כשאתה לוחץ על כפתור “+3”:
import { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 1); setNumber(number + 1); setNumber(number + 1); }}>+3</button> </> ) }
שימו לב ש’מספר’ עולה רק פעם אחת בכל קליק!
מצב המשנה את זה רק עבור העיבוד הבא. לאחר העיבוד הראשון, ‘מספר’ היה ‘0’. זה מה, ברופאonClick של *הרינדור הזה, הערך של number עדיין 0 גם לאחר שנקרא setNumber(number + 1):
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>הנה מה שרופא הלחיצה של הכפתור הזה ל-React אומר:
setNumber(number + 1):numberהוא0הואsetNumber(0 + 1).- React מתכונן את ‘מספר’ ל-‘1’ בעיבוד הבא.
setNumber(number + 1):numberהוא0הואsetNumber(0 + 1).- React מתכונן את ‘מספר’ ל-‘1’ בעיבוד הבא.
setNumber(number + 1):numberהוא0הואsetNumber(0 + 1).- React מתכונן לשנות את ‘מספר’ ל-‘1’ בעיבוד הבא.
למרות שקראת ‘setNumber(number + 1)’ שלוש פעמים, בטיפולים של העיבוד הזה הוא תמיד ‘0’, אז אתה מגדיר את הstate ל-‘1’ שלוש פעמים. זה מה שאחרי המטפל באירועים שלך מסיים, React מעבד מחדש את הרכיב עם ‘מספר’ שווה ל-‘1’ במקום ‘3’.
אתה יכול גם לדמיין זאת על ידי החלפה מנטלי של שני מצב עם הערכים שלהם בקוד שלך. מה שמשתנה הstate ‘מספר’ הוא ‘0’ עבור עיבוד הזה, רופא מטפלים שלו נראה כך:
<button onClick={() => {
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
}}>+3</button>עבור העיבוד הבא, מספר הוא 1, כך שמטפל הקליקים של העיבוד הזה נראה כך:
<button onClick={() => {
setNumber(1 + 1);
setNumber(1 + 1);
setNumber(1 + 1);
}}>+3</button>זו הסיבה שלחיצה נוספת על הכפתור תגדיר את המונה ל-‘2’, ואז ל-‘3’ בלחיצה הבאה, וכן הלאה.
מצב לאורך זמן
ובכן, זה היה כיף. נסה לנחש מה תתריע לחיצה על הכפתור הזה:
import { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 5); alert(number); }}>+5</button> </> ) }
אם אתה משתמש בשיטת ההחלפה מקודם, אתה יכול לנחש שההתראה מציגה “0”:
setNumber(0 + 5);
alert(0);אבל מה אם תכניס טיימר להתראה, אז הוא יופעל רק לאחר שהרכיב יוצג מחדש? האם יהיה כתוב “0” או “5”? יש לנחש!
import { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 5); setTimeout(() => { alert(number); }, 3000); }}>+5</button> </> ) }
מוּפתָע? אם אתה משתמש בשיטת ההחלפה, אתה יכול לראות את “תמונה הstate” של הstate שהועברה להתראה.
setNumber(0 + 5);
setTimeout(() => {
alert(0);
}, 3000);ייתכן שstate המאוחסן ב-React השתנה עד למועד הפעלת ההתראה, אבל זה תוכנן באמצעות תמונת מצב של הstate בזמן שהמשתמש קיים אינטראקציה!
הערך של שינוי מצב לעולם לא משתנה בתוך רינדור, גם אם הקוד של רופא הרופאים שלו הוא אסינכרוני. בתוך onClick של העיבוד, הערך של number ממשיך להיות 0 גם לאחר שנקרא setNumber(number + 5). הערך שלו “תוקן” כאשר React “לקח את תמונת הstate” של ממשק משתמש על ידי קריאה לרכיב שלך.
הנה דוגמה לאופן שבו זה גורם למטפלי האירועים שלך להיות פחות מועדים לטעויות תזמון. להלן טופס ששולח הודעה באיחור של חמש שניות. דמיינו את התרחיש הזה:
- אתה לוחץ על כפתור “שלח”, שולח “שלום” לאליס.
- לפני שהשהייה של חמש שניות מסתיימת, אתה משנה את הערך של השדה “To” ל-”Bob”.
מה אתה מצפה שה’התראה’ תציג? האם זה יציג, “אמרת שלום לאליס”? או שהוא יציג, “אמרת שלום לבוב”? עשה ניחוש על סמך מה שאתה יודע, ואז נסה את זה:
import { useState } from 'react'; export default function Form() { const [to, setTo] = useState('Alice'); const [message, setMessage] = useState('Hello'); function handleSubmit(e) { e.preventDefault(); setTimeout(() => { alert(`You said ${message} to ${to}`); }, 5000); } return ( <form onSubmit={handleSubmit}> <label> To:{' '} <select value={to} onChange={e => setTo(e.target.value)}> <option value="Alice">Alice</option> <option value="Bob">Bob</option> </select> </label> <textarea placeholder="Message" value={message} onChange={e => setMessage(e.target.value)} /> <button type="submit">Send</button> </form> ); }
React שומר על ערכי הstateקבועים” בתוך “רופאי קודים של רינדור אחד. אינך צריך לדאוג אם הstate השתנה בזמן שהפעיל.
אבל מה אם תרצה לקרוא את הstate האחרון לפני עיבוד מחדש? תרצה להשתמש בפונקציית עדכון מצב, המכוסה בעמוד הבא!
Recap
- הגדרת מצב מבקשת עיבוד חדש.
- חנויות מצב React מחוץ לרכיב שלך, כאילו על הדף.
- כאשר אתה קורא ‘useState’, React נותן לך תמונת מצב של הstate עבור העיבוד הזה.
- משתנים ומטפלי אירועים אינם “שורדים” עיבוד מחדש. לכל עיבוד יש מטפלי אירועים משלו.
- כל עיבוד (ומתפקד בתוכו) תמיד “יראה” את תמונת הstate של React נתנה לעיבוד זה.
- אתה יכול להחליף מצב נפשית במטפלי אירועים, בדומה לאופן שבו אתה חושב על ה-JSX המעובד.
- למטפלי אירועים עסקיים בעבר יש את ערכי הstate מה שבו הם נוצרו.
Challenge 1 of 1: יישם רמזור
להלן רכיב תאורה של מעבר חציה שמתחלף בעת לחיצה על הכפתור:
import { useState } from 'react'; export default function TrafficLight() { const [walk, setWalk] = useState(true); function handleClick() { setWalk(!walk); } return ( <> <button onClick={handleClick}> Change to {walk ? 'Stop' : 'Walk'} </button> <h1 style={{ color: walk ? 'darkgreen' : 'darkred' }}> {walk ? 'Walk' : 'Stop'} </h1> </> ); }
הוסף ‘התראה’ למטפל בלחיצה. כאשר האור ירוק ואומר “הליכה”, לחיצה על הכפתור אמורה לומר “עצירה היא הבאה”. כאשר האור אדום ואומר “עצור”, לחיצה על הכפתור אמורה לומר “הליכה היא הבאה”.
האם זה משנה אם אתה שם את ‘התראה’ לפני או אחרי שיחת ‘setWalk’?