Pitfall

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

Component היא המחלקה הבסיסית עבור רכיבי React המוגדרים כ-JavaScript מחלקות. רכיבי מחלקה עדיין נתמכים על ידי React, אך אנו לא ממליצים להשתמש בהם בקוד חדש.

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

הפניה

Component

כדי להגדיר רכיב React כמחלקה, הרחב את המחלקה המובנית Component והגדר שיטה render:

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

נדרשת רק שיטת render, שיטות אחרות הן אופציונליות.

ראה דוגמאות נוספות למטה.


context

ה-הקשר של רכיב מחלקה זמין בתור this.context. זה זמין רק אם אתה מציין איזה הקשר אתה רוצה לקבל באמצעות static contextType (מודרני) או static contextTypes (הוצא משימוש).

רכיב מחלקה יכול לקרוא רק הקשר אחד בכל פעם.

class Button extends Component {
static contextType = ThemeContext;

render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}

Note

קריאת this.context ברכיבי כיתה שווה ערך ל-useContext ברכיבי פונקציה.

ראה כיצד להעביר.


props

ה-props שהועברו לרכיב מחלקה זמינים בתור this.props.

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

<Greeting name="Taylor" />

Note

קריאת this.props ברכיבי הכיתה שווה ערך להכרזה על props ברכיבי פונקציה.

ראה כיצד להעביר.


refs

Deprecated

API זה יוסר בגרסה עיקרית עתידית של React. השתמש במקום זאת ב-createRef.

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


state

ה-state של רכיב מחלקה זמין בתור this.state. השדה state חייב להיות אובייקט. אל תשנה את ה-state ישירות. אם ברצונך לשנות את ה-state, התקשר ל-setState עם ה-state החדש.

class Counter extends Component {
state = {
age: 42,
};

handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};

render() {
return (
<>
<button onClick={this.handleAgeChange}>
Increment age
</button>
<p>You are {this.state.age}.</p>
</>
);
}
}

Note

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

ראה כיצד להעביר.


constructor(props)

קונסטרוקטור פועל לפני שרכיב המחלקה שלך מועלה (מתווסף למסך). בדרך כלל, בנאי הוא רק used לשתי מטרות ב-React. הוא מאפשר לך להכריז על state ו-bind שיטות המחלקה שלך למופע המחלקה:

class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
// ...
}

אם אתה use תחביר JavaScript מודרני, לעתים נדירות יש צורך בבנאים. במקום זאת, אתה יכול לשכתב את הקוד הזה למעלה באמצעות תחביר שדה הכיתה הציבורי שנתמך הן על ידי דפדפנים מודרניים והן על ידי כלים כמו Babel:

class Counter extends Component {
state = { counter: 0 };

handleClick = () => {
// ...
}

בנאי לא אמור להכיל תופעות לוואי או מנויים.

פרמטרים

  • props: ה-props הראשוני של הרכיב.

מחזירה

constructor לא אמור להחזיר כלום.

אזהרות

  • אל תפעיל תופעות לוואי או מנויים בבנאי. במקום זאת, use componentDidMount עבור זה.

  • בתוך קונסטרוקטור, אתה צריך לקרוא super(props) לפני כל statement אחר. אם לא תעשה זאת, this.props יהיה undefined בזמן שהקונסטרוקטור פועל, מה שיכול להיות מבלבל ו-cause באגים.

  • Constructor הוא המקום היחיד שבו אתה יכול להקצות את this.state ישירות. בכל שאר השיטות, אתה צריך use this.setState() במקום זאת. אל תקרא ל-setState בקונסטרוקטור.

  • כאשר אתה use עיבוד שרת, הבנאי יפעל גם על השרת, ואחריו השיטה render. עם זאת, שיטות מחזור חיים כמו componentDidMount או componentWillUnmount לא יפעלו בשרת.

  • כאשר מצב קפדני מופעל, React יתקשר ל-constructor פעמיים בפיתוח ולאחר מכן יזרוק את אחד מהמופעים. זה עוזר לך להבחין בתופעות הלוואי המקריות שיש להעביר מה-constructor.

Note

אין מקבילה מדויקת עבור constructor ברכיבי פונקציה. כדי להכריז על state ברכיב פונקציה, התקשר ל-useState. כדי להימנע מחישוב מחדש של ה-state הראשוני, העבירו פונקציה ל-useState.


componentDidCatch(error, info)

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

בדרך כלל, זה used יחד עם static getDerivedStateFromError המאפשר לך לעדכן את state בתגובה לשגיאה ולהציג הודעת שגיאה ל-user. רכיב עם שיטות אלה נקרא גבול שגיאה.

ראה דוגמה.

פרמטרים

  • error: השגיאה שנזרקה. בפועל, זה בדרך כלל יהיה מופע של Error אבל זה לא מובטח כיuse JavaScript מאפשר throw כל ערך, כולל מחרוזות או אפילו null.

  • info: אובייקט המכיל מידע נוסף על השגיאה. השדה componentStack שלו מכיל עקבות מחסנית עם הרכיב שזרק, כמו גם את השמות ומיקומי המקור של כל רכיבי האב שלו. בייצור, שמות הרכיבים יוקטנו. אם תגדיר דיווח על שגיאות ייצור, תוכל לפענח את ערימת הרכיבים באמצעות מפות מקור באותו אופן כפי שהיית עושה עבור ערימות שגיאות JavaScript רגילות.

מחזירה

componentDidCatch לא אמור להחזיר כלום.

אזהרות

  • בעבר, היה מקובל לקרוא ל-setState בתוך componentDidCatch על מנת לעדכן את ממשק המשתמש ולהציג את הודעת השגיאה החלפה. זה הוצא משימוש לטובת הגדרת static getDerivedStateFromError.

  • ייצור ופיתוח של React שונים מעט באופן שבו componentDidCatch מטפל בשגיאות. בפיתוח, השגיאות יבעבעו עד window, מה שאומר שכל window.onerror או window.addEventListener('error', callback) יירטו את השגיאות שנתפסו על ידי componentDidCatch. בייצור, במקום זאת, השגיאות לא יבעבעו, מה שאומר שכל מטפל בשגיאות קדמון יקבל רק שגיאות שלא נתפסו במפורש על ידי componentDidCatch.

Note

עדיין אין מקבילה ישירה עבור componentDidCatch ברכיבי פונקציה. אם תרצה להימנע מיצירת רכיבי מחלקה, כתוב רכיב ErrorBoundary יחיד כמו למעלה וuse אותו בכל האפליקציה שלך. לחלופין, אתה יכול use את החבילה react-error-boundary שעושה את זה בשבילך.


componentDidMount()

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

אם אתה מיישם componentDidMount, אתה בדרך כלל צריך ליישם שיטות מחזור חיים אחרות כדי למנוע באגים. לדוגמה, אם componentDidMount קורא כמה state או props, אתה גם צריך ליישם את componentDidUpdate כדי לטפל בשינויים שלהם, ו-componentWillUnmount כדי לנקות את כל מה שcomponentDidMount עשה.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

ראה דוגמאות נוספות.

פרמטרים

componentDidMount אינו לוקח פרמטרים כלשהם.

מחזירה

componentDidMount לא אמור להחזיר כלום.

אזהרות

  • כאשר מצב קפדני פועל, בפיתוח React יתקשר ל-componentDidMount, ואז יתקשר מיד ל-componentWillUnmount, ואז יתקשר שוב ל-componentDidMount. זה עוזר לך לשים לב אם שכחת ליישם את componentWillUnmount או שהלוגיקה שלו לא “משקפת” את מה שcomponentDidMount עושה.

  • למרות שאתה יכול להתקשר ל-setState מיד ב-componentDidMount, עדיף להימנע מכך כשאפשר. זה יפעיל עיבוד נוסף, אבל זה יקרה לפני שהדפדפן יעדכן את המסך. זה מבטיח שלמרות שה-render ייקרא פעמיים במקרה זה, ה-user לא יראה את state הביניים. השתמש בדפוס זה בזהירות מכיוון שuse לעתים קרובות יש בעיות בביצועים. ברוב המקרים, אתה אמור להיות מסוגל להקצות את ה-state הראשוני ב-constructor במקום זאת. עם זאת, זה יכול להיות נחוץ עבור מקרים כמו מודלים ועצות כלים כאשר אתה צריך למדוד צומת DOM לפני עיבוד משהו שתלוי בגודל או במיקומו.

Note

עבור מקרים רבים של use, הגדרת componentDidMount, componentDidUpdate וcomponentWillUnmount יחד ברכיבי מחלקה שווה ערך לקריאה ל-useEffect ברכיבי פונקציה. במקרים נדירים שבהם חשוב שהקוד ירוץ לפני צבע הדפדפן, useLayoutEffect הוא התאמה קרובה יותר.

ראה כיצד להעביר.


componentDidUpdate(prevProps, prevState, snapshot?)

אם תגדיר את שיטת componentDidUpdate, React יקרא לה מיד לאחר שהרכיב שלך יעובד מחדש עם props או state מעודכן. שיטה זו אינה נקראת עבור העיבוד הראשוני.

אתה יכול use אותו כדי לתפעל את ה-DOM לאחר עדכון. זהו גם מקום נפוץ לבצע בקשות רשת כל עוד אתה משווה את ה-props הנוכחי ל-props הקודם (למשל, בקשת רשת לא תהיה נחוצה אם ה-props לא השתנה). בדרך כלל, use זה יחד עם componentDidMount ו-componentWillUnmount:

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

ראה דוגמאות נוספות.

פרמטרים

  • prevProps: אביזרים לפני העדכון. השווה את prevProps ל-this.props כדי לקבוע מה השתנה.

  • prevState: מצב לפני העדכון. השווה את prevState ל-this.state כדי לקבוע מה השתנה.

  • snapshot: אם יישמת את getSnapshotBeforeUpdate, snapshot יכיל את הערך שהחזרת משיטה זו. אחרת, זה יהיה undefined.

מחזירה

componentDidUpdate לא אמור להחזיר כלום.

אזהרות

  • componentDidUpdate לא ייקרא אם הוגדר shouldComponentUpdate ויחזיר את false.

  • ההיגיון בתוך componentDidUpdate בדרך כלל צריך להיות עטוף בתנאים המשווים this.props עם prevProps, וthis.state עם prevState. אחרת, יש סיכון ליצירת לולאות אינסופיות.

  • למרות שאתה יכול להתקשר ל-setState מיד ב-componentDidUpdate, עדיף להימנע מכך כשאפשר. זה יפעיל עיבוד נוסף, אבל זה יקרה לפני שהדפדפן יעדכן את המסך. זה מבטיח שלמרות שה-render ייקרא פעמיים במקרה זה, ה-user לא יראה את state הביניים. דפוס זה גורם לרוב לבעיות ביצועים של __TK_7, אך ייתכן שיהיה צורך במקרים נדירים כמו מודלים וטיפים של כלים כאשר אתה צריך למדוד צומת DOM לפני עיבוד משהו שתלוי בגודלו או במיקומו.

Note

עבור מקרים רבים של use, הגדרת componentDidMount, componentDidUpdate וcomponentWillUnmount יחד ברכיבי מחלקה שווה ערך לקריאה ל-useEffect ברכיבי פונקציה. במקרים נדירים שבהם חשוב שהקוד ירוץ לפני צבע הדפדפן, useLayoutEffect הוא התאמה קרובה יותר.

ראה כיצד להעביר.


componentWillMount()

Deprecated

שם ה-API הזה שונה מ-componentWillMount ל-UNSAFE_componentWillMount. השם הישן הוצא משימוש. בגרסה עיקרית עתידית של React, רק השם החדש יעבוד.

הפעל את rename-unsafe-lifecycles codemod כדי לעדכן אוטומטית את הרכיבים שלך.


componentWillReceiveProps(nextProps)

Deprecated

השם ה-API הזה שונה מ-componentWillReceiveProps ל-UNSAFE_componentWillReceiveProps. השם הישן הוצא משימוש. בגרסה עיקרית עתידית של React, רק השם החדש יעבוד.

הפעל את rename-unsafe-lifecycles codemod כדי לעדכן אוטומטית את הרכיבים שלך.


componentWillUpdate(nextProps, nextState)

Deprecated

שם ה-API הזה שונה מ-componentWillUpdate ל-UNSAFE_componentWillUpdate. השם הישן הוצא משימוש. בגרסה עיקרית עתידית של React, רק השם החדש יעבוד.

הפעל את rename-unsafe-lifecycles codemod כדי לעדכן אוטומטית את הרכיבים שלך.


componentWillUnmount()

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

ההיגיון בתוך componentWillUnmount צריך “לשקף” את ההיגיון בתוך componentDidMount. לדוגמה, אם componentDidMount מגדיר מנוי, componentWillUnmount צריך לנקות את המנוי הזה. אם לוגיקת הניקוי ב-componentWillUnmount שלך קוראת כמה props או state, בדרך כלל תצטרך ליישם גם componentDidUpdate כדי לנקות משאבים (כגון מנויים) התואמים ל-props ול-state הישנים.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

ראה דוגמאות נוספות.

פרמטרים

componentWillUnmount אינו לוקח פרמטרים כלשהם.

מחזירה

componentWillUnmount לא אמור להחזיר כלום.

אזהרות

  • כאשר מצב קפדני פועל, בפיתוח React יתקשר ל-componentDidMount, ואז יתקשר מיד ל-componentWillUnmount, ואז יתקשר שוב ל-componentDidMount. זה עוזר לך לשים לב אם שכחת ליישם את componentWillUnmount או שהלוגיקה שלו לא “משקפת” את מה שcomponentDidMount עושה.

Note

עבור מקרים רבים של use, הגדרת componentDidMount, componentDidUpdate וcomponentWillUnmount יחד ברכיבי מחלקה שווה ערך לקריאה ל-useEffect ברכיבי פונקציה. במקרים נדירים שבהם חשוב שהקוד ירוץ לפני צבע הדפדפן, useLayoutEffect הוא התאמה קרובה יותר.

ראה כיצד להעביר.


forceUpdate(callback?)

מאלץ רכיב לעיבוד מחדש.

בדרך כלל, זה לא הכרחי. אם השיטה render של הרכיב שלך קוראת רק מ-this.props, this.state, או this.context, היא תוצג מחדש באופן אוטומטי כאשר תקרא ל-[setState](#props](#__)__K של אחד מההורים שלך. עם זאת, אם שיטת render של הרכיב שלך קוראת ישירות ממקור נתונים חיצוני, עליך להורות לReact לעדכן את ממשק user כאשר מקור נתונים זה משתנה. זה מה שforceUpdate מאפשר לך לעשות.

נסו להימנע מכל uses של forceUpdate וקראו רק מthis.props וthis.state בrender.

פרמטרים

  • אופציונלי callback אם צוין, React יתקשר ל-callback שסיפקת לאחר ביצוע העדכון.

מחזירה

forceUpdate לא מחזיר כלום.

אזהרות

Note

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


getChildContext()

Deprecated

API זה יוסר בגרסה עיקרית עתידית של React. השתמש במקום זאת ב-Context.Provider.

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


getSnapshotBeforeUpdate(prevProps, prevState)

אם תטמיע את getSnapshotBeforeUpdate, React יתקשר אליו מיד לפני ש-React יעדכן את ה-DOM. זה מאפשר לרכיב שלך ללכוד מידע מה-DOM (למשל מיקום הגלילה) לפני שהוא משתנה באופן פוטנציאלי. כל ערך שיוחזר על ידי שיטת מחזור חיים זו יועבר כפרמטר אל componentDidUpdate.

לדוגמה, אתה יכול use אותו בממשק משתמש כמו שרשור צ’אט שצריך לשמור על מיקום הגלילה שלו במהלך עדכונים:

class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}

componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}

render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}

בדוגמה לעיל, חשוב לקרוא את המאפיין scrollHeight ישירות ב-getSnapshotBeforeUpdate. זה לא בטוח לקרוא אותו ב-render, UNSAFE_componentWillReceiveProps, או UNSAFE_componentWillUpdate כי use קיים פער זמן פוטנציאלי בין התקשרות לשיטות אלו לבין עדכון KReact.

פרמטרים

  • prevProps: אביזרים לפני העדכון. השווה את prevProps ל-this.props כדי לקבוע מה השתנה.

  • prevState: מצב לפני העדכון. השווה את prevState ל-this.state כדי לקבוע מה השתנה.

מחזירה

עליך להחזיר ערך תמונת מצב מכל סוג שתרצה, או null. הערך שהחזרת יועבר כארגומנט השלישי אל componentDidUpdate.

אזהרות

Note

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


render()

שיטת render היא השיטה הנדרשת היחידה ברכיב מחלקה.

השיטה render צריכה לציין מה ברצונך שיופיע על המסך, לדוגמה:

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

React עשוי להתקשר ל-render בכל רגע, אז אל תניח שהוא פועל בזמן מסוים. בדרך כלל, השיטה render צריכה להחזיר חתיכה של JSX, אבל כמה סוגי החזרות אחרים (כמו מחרוזות) נתמכים. כדי לחשב את ה-JSX המוחזר, שיטת render יכולה לקרוא this.props, this.state ו-this.context.

עליך לכתוב את שיטת render כפונקציה טהורה, כלומר היא צריכה להחזיר את אותה תוצאה אם ​​props, state והקשר זהים. זה גם לא אמור להכיל תופעות לוואי (כמו הגדרת מנויים) או לקיים אינטראקציה עם APIs של הדפדפן. תופעות לוואי צריכות להתרחש במטפלי אירועים או בשיטות כמו componentDidMount.

פרמטרים

render אינו לוקח פרמטרים כלשהם.

מחזירה

render יכול להחזיר כל צומת React חוקי. זה כולל אלמנטים React כגון <div />, מחרוזות, מספרים, פורטלים, צמתים ריקים (null, undefined, true ו-false), ומערכים של React nodes.

אזהרות

  • יש לכתוב את render כפונקציה טהורה של props, state והקשר. לא אמורות להיות לזה תופעות לוואי.

  • render לא ייקרא אם הוגדר shouldComponentUpdate ויחזיר את false.

  • כאשר מצב קפדני פועל, React יתקשר ל-render פעמיים בפיתוח ולאחר מכן יזרוק אחת מהתוצאות. זה עוזר לך להבחין בתופעות הלוואי המקריות שיש להזיז משיטת render.

  • אין התכתבות של אחד על אחד בין שיחת render לשיחת componentDidMount או componentDidUpdate שלאחר מכן. חלק מתוצאות השיחה render עשויות להימחק על ידי React כאשר זה מועיל.


setState(nextState, callback?)

התקשר ל-setState כדי לעדכן את ה-state של רכיב ה-React שלך.

class Form extends Component {
state = {
name: 'Taylor',
};

handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}

render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Hello, {this.state.name}.</p>
</>
);
}
}

setState מציב שינויים בתורים ברכיב state. זה אומר לReact שהרכיב הזה והילדים שלו צריכים לעבד מחדש עם ה-state החדש. זו הדרך העיקרית שבה תעדכן את ממשק user בתגובה לאינטראקציות.

Pitfall

קריאה ל-setState לא משנה את ה-state הנוכחי בקוד שכבר מבצע:

function handleClick() {
console.log(this.state.name); // "Taylor"
this.setState({
name: 'Robin'
});
console.log(this.state.name); // Still "Taylor"!
}

זה משפיע רק על מה שthis.state יחזיר החל מהעיבוד הבא.

אתה יכול גם להעביר פונקציה ל-setState. זה מאפשר לך לעדכן את state על סמך ה-state הקודם:

handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}

אתה לא חייב לעשות זאת, אבל זה שימושי אם אתה רוצה לעדכן את state מספר פעמים במהלך אותו אירוע.

פרמטרים

  • nextState: או אובייקט או פונקציה.

    • אם תעביר אובייקט בתור nextState, הוא יתמזג בצורה רדודה לתוך this.state.
    • אם תעביר פונקציה בתור nextState, היא תטופל כאל פונקציית עדכון. זה חייב להיות טהור, צריך לקחת את state וprops הממתינים כארגומנטים, ועליו להחזיר את האובייקט למיזוג רדוד לתוך this.state. React ישים את פונקציית העדכון שלך בתור ותעבד מחדש את הרכיב שלך. במהלך העיבוד הבא, React יחשב את ה-state הבא על ידי החלת כל העדכונים בתור על ה-state הקודם.
  • אופציונלי callback: אם צוין, React יתקשר ל-callback שסיפקת לאחר ביצוע העדכון.

מחזירה

setState לא מחזיר כלום.

אזהרות

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

  • setState does not update this.state immediately. זה הופך את הקריאה של this.state מיד לאחר הקריאה ל-setState למלכודת פוטנציאלית. במקום זאת, use componentDidUpdate או הארגומנט setState callback, שכל אחד מהם מובטח יופעל לאחר החלת העדכון. אם אתה צריך להגדיר את state בהתבסס על ה-state הקודם, תוכל להעביר פונקציה ל-nextState כמתואר לעיל.

Note

קריאה ל-setState ברכיבי מחלקה דומה לקריאה לפונקציה set ברכיבי פונקציה.

ראה כיצד להעביר.


shouldComponentUpdate(nextProps, nextState, nextContext)

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

אם אתה בטוח שאתה רוצה לכתוב את זה ביד, אתה יכול להשוות את this.props עם nextProps וthis.state עם nextState ולהחזיר את false כדי לומר לReact שניתן לדלג על העדכון.

class Rectangle extends Component {
state = {
isHovered: false
};

shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// Nothing has changed, so a re-render is unnecessary
return false;
}
return true;
}

// ...
}

React קורא ל-shouldComponentUpdate לפני העיבוד כאשר props או state חדשים מתקבלים. ברירת המחדל היא true. שיטה זו אינה נקראת עבור העיבוד הראשוני או כאשר forceUpdate הוא used.

פרמטרים

  • nextProps: ה-props הבא שאיתו הרכיב עומד לרנדר. השווה את nextProps ל-this.props כדי לקבוע מה השתנה.
  • nextState: ה-state הבא שאיתו הרכיב עומד לרנדר. השווה את nextState ל-this.state כדי לקבוע מה השתנה.
  • nextContext: ההקשר הבא שאיתו הרכיב עומד לרנדר. השווה את nextContext ל-this.context כדי לקבוע מה השתנה. זמין רק אם אתה מציין static contextType (מודרני) או static contextTypes (מדור קודם).

מחזירה

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

החזר false כדי לומר לReact שניתן לדלג על עיבוד מחדש.

אזהרות

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

  • שקול להשתמש ב-PureComponent במקום לכתוב shouldComponentUpdate ביד. PureComponent משווה באופן רדוד בין props ל-state, ומקטינה את הסיכוי שתדלג על עדכון הכרחי.

  • איננו ממליצים לבצע בדיקות שוויון עמוקות או להשתמש ב-JSON.stringify ב-shouldComponentUpdate. זה הופך את הביצועים לבלתי צפויים ותלויים במבנה הנתונים של כל אביזר ו-state. במקרה הטוב, אתה מסתכן בהחדרת דוכנים של מספר שניות לאפליקציה שלך, ובמקרה הגרוע אתה מסתכן בקריסתה.

  • החזרת false אינה מונעת רכיבי צאצא לבצע רינדור מחדש כאשר state שלהם משתנה.

  • החזרת false אינה מבטיחה שהרכיב לא יעבד מחדש. React יעשה use את ערך ההחזרה כרמז, אבל הוא עדיין עשוי לבחור לעבד מחדש את הרכיב שלך אם יש טעם לעשות זאת מסיבות אחרות.

Note

אופטימיזציה של רכיבי כיתה עם shouldComponentUpdate דומה לאופטימיזציה של רכיבי פונקציה עם memo. רכיבי פונקציה מציעים גם אופטימיזציה פרטנית יותר עם useMemo.


UNSAFE_componentWillMount()

אם תגדיר UNSAFE_componentWillMount, React יקרא לו מיד אחרי ה-constructor. זה קיים רק מסיבות היסטוריות ולא צריך להיות used בשום קוד חדש. במקום זאת, use אחת מהחלופות:

  • כדי לאתחל את state, הכריז על state כשדות מחלקה או הגדר this.state בתוך constructor.
  • אם אתה צריך להפעיל תופעת לוואי או להגדיר מנוי, העבר את ההיגיון הזה ל-componentDidMount במקום זאת.

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

פרמטרים

UNSAFE_componentWillMount אינו לוקח פרמטרים כלשהם.

מחזירה

UNSAFE_componentWillMount לא אמור להחזיר כלום.

אזהרות

  • UNSAFE_componentWillMount לא ייקרא אם הרכיב מיישם static getDerivedStateFromProps או getSnapshotBeforeUpdate.

  • למרות השם שלו, UNSAFE_componentWillMount לא מבטיח שהרכיב יותקן אם האפליקציה שלך תכלול את התכונות המודרניות React של האפליקציה שלך כמו Suspense. אם ניסיון עיבוד מושעה (לדוגמה, בגלל שהקוד לא טען עדיין use עבור חלק מהילד) React יזרוק את העץ שנמצא בתהליך וינסה לבנות את הרכיב מאפס במהלך הניסיון הבא. זו הסיבה שהשיטה הזו “לא בטוחה”. קוד שמסתמך על הרכבה (כמו הוספת מנוי) צריך להיכנס אל componentDidMount.

  • UNSAFE_componentWillMount היא שיטת מחזור החיים היחידה שפועלת במהלך עיבוד שרת. לכל המטרות המעשיות, היא זהה ל-constructor, אז כדאי use את constructor עבור סוג זה של לוגיקה במקום זאת.

Note

קריאה ל-setState בתוך UNSAFE_componentWillMount ברכיב מחלקה לאתחול state שווה ערך להעברת state זה בתור state ההתחלתי ל-useState ברכיב פונקציה


UNSAFE_componentWillReceiveProps(nextProps, nextContext)

אם תגדיר UNSAFE_componentWillReceiveProps, React יקרא לו כאשר הרכיב יקבל props חדש. זה קיים רק מסיבות היסטוריות ולא אמור להיות used בשום קוד חדש. במקום זאת, use אחת מהחלופות:

  • אם אתה צריך להפעיל תופעת לוואי (לדוגמה, להביא נתונים, להפעיל אנימציה או לאתחל מחדש מנוי) בתגובה לשינויים באביזרי, העבר את ההיגיון הזה ל-componentDidUpdate במקום זאת.
  • אם אתה צריך להימנע מחישוב מחדש של חלק מהנתונים רק כאשר אבזר משתנה, use memoמסייע לאיזון במקום זאת.
  • אם אתה צריך “לאפס” כמה state כאשר אבזר משתנה, שקול ליצור רכיב בשליטה מלאה או לא מבוקר לחלוטין עם מפתח במקום זאת.
  • אם אתה צריך “להתאים” כמה state כאשר אבזר משתנה, בדוק אם אתה יכול לחשב את כל המידע הדרוש מ-props לבד במהלך העיבוד. אם אינך יכול, use static getDerivedStateFromProps במקום זאת.

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

פרמטרים

  • nextProps: ה-props הבא שהרכיב עומד לקבל מהרכיב האב שלו. השווה את nextProps ל-this.props כדי לקבוע מה השתנה.
  • nextContext: ההקשר הבא שהרכיב עומד לקבל מהספק הקרוב ביותר. השווה את nextContext ל-this.context כדי לקבוע מה השתנה. זמין רק אם אתה מציין static contextType (מודרני) או static contextTypes (מדור קודם).

מחזירה

UNSAFE_componentWillReceiveProps לא אמור להחזיר כלום.

אזהרות

  • UNSAFE_componentWillReceiveProps לא ייקרא אם הרכיב מיישם static getDerivedStateFromProps או getSnapshotBeforeUpdate.

  • למרות השם שלו, UNSAFE_componentWillReceiveProps אינו מבטיח שהרכיב יקבל את ה-props האלה אם האפליקציה שלך use של התכונות המודרניות של React כמו Suspense. אם ניסיון רינדור הושעה (לדוגמה, רכיב __9 של האפליקציה עדיין לא הושעה, למשל, רכיב K __T לא הושעה), React יזרוק את העץ שנמצא בתהליך וינסה לבנות את הרכיב מאפס במהלך הניסיון הבא. עד לניסיון העיבוד הבא, ה-props עשוי להיות שונה. זו הסיבה שהשיטה הזו “לא בטוחה”. קוד שאמור לפעול רק עבור עדכונים מחויבים (כמו איפוס מנוי) צריך להיכנס אל componentDidUpdate.

  • UNSAFE_componentWillReceiveProps לא אומר שהרכיב קיבל props שונה מהפעם הקודמת. אתה צריך להשוות את nextProps וthis.props בעצמך כדי לבדוק אם משהו השתנה.

  • React לא קורא UNSAFE_componentWillReceiveProps עם props ראשוני במהלך ההרכבה. זה קורא לשיטה זו רק אם חלק מה-props של הרכיב עומדים להתעדכן. לדוגמה, קריאה ל-setState לא מפעילה בדרך כלל את UNSAFE_componentWillReceiveProps בתוך אותו רכיב.

Note

קריאה ל-setState בתוך UNSAFE_componentWillReceiveProps ברכיב מחלקה כדי “להתאים” state שווה ערך ל[קריאה לפונקציה set מuseState במהלך העיבוד](/reference/react/useState#rendering-information inv-component previous-component)


UNSAFE_componentWillUpdate(nextProps, nextState)

אם תגדיר UNSAFE_componentWillUpdate, React יקרא לזה לפני עיבוד עם props או state החדשים. זה קיים רק מסיבות היסטוריות ולא אמור להיות used בשום קוד חדש. במקום זאת, use אחת מהחלופות:

  • אם אתה צריך להפעיל תופעת לוואי (לדוגמה, להביא נתונים, להפעיל אנימציה או לאתחל מחדש מנוי) בתגובה לשינויים ב-prop או state, העבר את ההיגיון הזה ל-componentDidUpdate במקום זאת.
  • אם אתה צריך לקרוא מידע מה-DOM (לדוגמה, כדי לשמור את מיקום הגלילה הנוכחי) כדי שתוכל use אותו ב-componentDidUpdate מאוחר יותר, קרא אותו בתוך getSnapshotBeforeUpdate במקום זאת.

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

פרמטרים

  • nextProps: ה-props הבא שהרכיב עומד לעבד איתו. השווה את nextProps ל-this.props כדי לקבוע מה השתנה.
  • nextState: ה-state הבא שהרכיב עומד לעבד איתו. השווה את nextState ל-this.state כדי לקבוע מה השתנה.

מחזירה

UNSAFE_componentWillUpdate לא אמור להחזיר כלום.

אזהרות

  • UNSAFE_componentWillUpdate לא ייקרא אם הוגדר shouldComponentUpdate ויחזיר את false.

  • UNSAFE_componentWillUpdate לא ייקרא אם הרכיב מיישם static getDerivedStateFromProps או getSnapshotBeforeUpdate.

  • אין תמיכה להתקשר ל-setState (או כל שיטה שמובילה לקריאה של setState, כמו שליחת פעולת Redux) במהלך componentWillUpdate.

  • למרות השם שלו, UNSAFE_componentWillUpdate אינו מבטיח שהרכיב יתעדכן אם האפליקציה שלך use תכונות מודרניות של React כמו Suspense. אם ניסיון רינדור מושעה (לדוגמה, בגלל use של האפליקציה שלך use הרכיב הילד __5 עדיין לא יטען __T רכיב 5) הרחק את העץ בתהליך ונסה לבנות את הרכיב מאפס במהלך הניסיון הבא. עד לניסיון העיבוד הבא, props וstate עשויים להיות שונים. זו הסיבה שהשיטה הזו “לא בטוחה”. קוד שאמור לפעול רק עבור עדכונים מחויבים (כמו איפוס מנוי) צריך להיכנס אל componentDidUpdate.

  • UNSAFE_componentWillUpdate לא אומר שהרכיב קיבל props או state שונה מהפעם הקודמת. אתה צריך להשוות את nextProps עם this.props וnextState עם this.state בעצמך כדי לבדוק אם משהו השתנה.

  • React לא קורא UNSAFE_componentWillUpdate עם props וstate ראשוני במהלך ההרכבה.

Note

אין מקבילה ישירה ל-UNSAFE_componentWillUpdate ברכיבי פונקציה.


static childContextTypes

Deprecated

API זה יוסר בגרסה עיקרית עתידית של React. השתמש במקום זאת ב-static contextType.

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


static contextTypes

Deprecated

API זה יוסר בגרסה עיקרית עתידית של React. השתמש במקום זאת ב-static contextType.

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


static contextType

אם אתה רוצה לקרוא את this.context מרכיב הכיתה שלך, עליך לציין איזה הקשר הוא צריך לקרוא. ההקשר שאתה מציין בתור static contextType חייב להיות ערך שנוצר בעבר על ידי createContext.

class Button extends Component {
static contextType = ThemeContext;

render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}

Note

קריאת this.context ברכיבי כיתה שווה ערך ל-useContext ברכיבי פונקציה.

ראה כיצד להעביר.


static defaultProps

אתה יכול להגדיר static defaultProps כדי להגדיר את ברירת המחדל props עבור המחלקה. הם יהיו used עבור undefined וחסרים props, אך לא עבור null props.

לדוגמה, כך אתה מגדיר שהאבזר color צריך כברירת מחדל ל-'blue':

class Button extends Component {
static defaultProps = {
color: 'blue'
};

render() {
return <button className={this.props.color}>click me</button>;
}
}

אם הפריט color אינו מסופק או שהוא undefined, הוא יוגדר כברירת מחדל ל-'blue':

<>
{/* this.props.color is "blue" */}
<Button />

{/* this.props.color is "blue" */}
<Button color={undefined} />

{/* this.props.color is null */}
<Button color={null} />

{/* this.props.color is "red" */}
<Button color="red" />
</>

Note

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


static propTypes

אתה יכול להגדיר static propTypes יחד עם ספריית prop-types כדי להצהיר על סוגי ה-props המקובלים על הרכיב שלך. סוגים אלו ייבדקו במהלך העיבוד ובפיתוח בלבד.

import PropTypes from 'prop-types';

class Greeting extends React.Component {
static propTypes = {
name: PropTypes.string
};

render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}

Note

אנו ממליצים להשתמש ב-TypeScript במקום לבדוק סוגי אביזרים בזמן ריצה.


static getDerivedStateFromError(error)

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

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

ראה דוגמה.

פרמטרים

  • error: השגיאה שנזרקה. בפועל, זה בדרך כלל יהיה מופע של Error אבל זה לא מובטח כיuse JavaScript מאפשר throw כל ערך, כולל מחרוזות או אפילו null.

מחזירה

static getDerivedStateFromError צריך להחזיר את ה-state ואומר לרכיב להציג את הודעת השגיאה.

אזהרות

  • static getDerivedStateFromError צריכה להיות פונקציה טהורה. אם אתה רוצה לבצע תופעת לוואי (לדוגמה, להתקשר לשירות ניתוח), עליך ליישם גם componentDidCatch.

Note

עדיין אין מקבילה ישירה עבור static getDerivedStateFromError ברכיבי פונקציה. אם תרצה להימנע מיצירת רכיבי מחלקה, כתוב רכיב ErrorBoundary יחיד כמו למעלה וuse אותו בכל האפליקציה שלך. לחלופין, use החבילה react-error-boundary שעושה את זה.


static getDerivedStateFromProps(props, state)

אם תגדיר static getDerivedStateFromProps, React יקרא לזה ממש לפני הקריאה ל-render, הן בהרכבה הראשונית והן בעדכונים הבאים. זה אמור להחזיר אובייקט כדי לעדכן את ה-state, או null כדי לעדכן כלום.

שיטה זו קיימת עבור מקרים נדירים של use כאשר ה-state תלוי בשינויים ב-props לאורך זמן. לדוגמה, רכיב Form זה מאפס את ה-email state כאשר מאפיין userID משתנה:

class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};

static getDerivedStateFromProps(props, state) {
// Any time the current user changes,
// Reset any parts of state that are tied to that user.
// In this simple example, that's just the email.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}

// ...
}

שים לב שתבנית זו מחייבת אותך לשמור ערך קודם של הפרופס (כמו userID) ב-state (כמו prevUserID).

Pitfall

גזירת state מובילה לקוד מילולי ומקשה על המחשבה על הרכיבים שלך. ודא שאתה מכיר חלופות פשוטות יותר:

פרמטרים

  • props: ה-props הבא שאיתו הרכיב עומד לרנדר.
  • state: ה-state הבא שהרכיב עומד לעשות איתו.

מחזירה

static getDerivedStateFromProps להחזיר אובייקט כדי לעדכן את ה-state, או null כדי לעדכן כלום.

אזהרות

  • שיטה זו מופעלת על כל רינדור, ללא קשר ל-cause. זה שונה מ-UNSAFE_componentWillReceiveProps, המופעל רק כאשר האב מבצע עיבוד מחדש ולא כתוצאה מ-setState מקומי.

  • לשיטה זו אין גישה למופע הרכיב. אם תרצה, תוכל מחדשuse קוד כלשהו בין static getDerivedStateFromProps לשיטות המחלקה האחרות על ידי חילוץ פונקציות טהורות של הרכיב props וstate מחוץ להגדרת המחלקה.

Note

יישום static getDerivedStateFromProps ברכיב מחלקה שווה ערך לקריאה לפונקציה set מ-useState במהלך העיבוד ברכיב פונקציה.


שימוש

הגדרת רכיב מחלקה

כדי להגדיר רכיב React כמחלקה, הרחב את המחלקה המובנית Component והגדר שיטה render:

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

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

בדומה לרכיבי פונקציה, רכיב מחלקה יכול לקבל מידע על ידי props מהרכיב האב שלו. עם זאת, התחביר לקריאת props שונה. לדוגמה, אם רכיב האב מעבד את <Greeting name="Taylor" />, אז אתה יכול לקרוא את האביזר name מ-this.props, כמו this.props.name:

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

שים לב ש-Hooks (פונקציות שמתחילות ב-use, כמו useState) אינן נתמכות בתוך רכיבי מחלקה.

Pitfall

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


הוספת state לרכיב מחלקה

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

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = () => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

Pitfall

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


הוספת שיטות מחזור חיים לרכיב מחלקה

יש כמה שיטות מיוחדות שאתה יכול להגדיר בכיתה שלך.

אם תגדיר את שיטת componentDidMount, React יקרא לה כאשר הרכיב שלך יתווסף (רכוב) למסך. React יקרא ל-componentDidUpdate לאחר שהרכיב שלך יעבד מחדש עקב שינוי ב-props או state. React יקרא ל-componentWillUnmount לאחר שהרכיב שלך הוסר (לא מותקן) מהמסך.

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

לדוגמה, רכיב ChatRoom זה שומר על חיבור צ’אט מסונכרן עם props וstate:

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

שים לב שבפיתוח כאשר מצב קפדני פועל, React יתקשר ל-componentDidMount, יתקשר מיד ל-componentWillUnmount, ואז יתקשר שוב ל-componentDidMount. זה עוזר לך לשים לב אם שכחת ליישם את componentWillUnmount או שהלוגיקה שלו לא “משקפת” את מה שcomponentDidMount עושה.

Pitfall

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


תופסת שגיאות רינדור עם גבול שגיאה

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

כדי ליישם רכיב גבול שגיאה, עליך לספק static getDerivedStateFromError המאפשר לך לעדכן את state בתגובה לשגיאה ולהציג הודעת שגיאה ל-user. אתה יכול גם ליישם אופציונלי componentDidCatch כדי להוסיף קצת היגיון נוסף, למשל, כדי להתחבר לשגיאה לשירות ניתוח.

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

componentDidCatch(error, info) {
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logErrorToMyService(error, info.componentStack);
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback;
}

return this.props.children;
}
}

לאחר מכן תוכל לעטוף בו חלק מעץ הרכיבים שלך:

<ErrorBoundary fallback={<p>Something went wrong</p>}>
<Profile />
</ErrorBoundary>

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

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

Note

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


חלופות

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

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

לדוגמה, נניח שאתה ממיר את רכיב המחלקה Greeting הזה לפונקציה:

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

הגדר פונקציה בשם Greeting. זה המקום שבו תעביר את גוף הפונקציה render שלך.

function Greeting() {
// ... move the code from the render method here ...
}

במקום this.props.name, הגדר את הפרופס name באמצעות תחביר ההרס וקרא אותו ישירות:

function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}

הנה דוגמה מלאה:

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}


העברת רכיב עם state ממחלקה לפונקציה

נניח שאתה ממיר את רכיב המחלקה Counter הזה לפונקציה:

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = (e) => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

התחל בהכרזה על פונקציה עם המשתנים הנחוצים state:

import { useState } from 'react';

function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...

לאחר מכן, המר את מטפלי האירועים:

function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);

function handleNameChange(e) {
setName(e.target.value);
}

function handleAgeChange() {
setAge(age + 1);
}
// ...

לבסוף, החלף את כל ההפניות שמתחילות ב-this במשתנים ובפונקציות שהגדרת ברכיב שלך. לדוגמה, החלף את this.state.age ב-age, והחלף את this.handleNameChange ב-handleNameChange.

להלן רכיב שעבר המרה מלאה:

import { useState } from 'react';

export default function Counter() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);

  function handleNameChange(e) {
    setName(e.target.value);
  }

  function handleAgeChange() {
    setAge(age + 1);
  }

  return (
    <>
      <input
        value={name}
        onChange={handleNameChange}
      />
      <button onClick={handleAgeChange}>
        Increment age
      </button>
      <p>Hello, {name}. You are {age}.</p>
    </>
  )
}


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

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

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

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

לאחר מכן, ודא ששיטת ה-componentDidUpdate שלך מטפלת בשינויים בכל props וstate שבה אתה משתמש ב-componentDidMount. בדוגמה שלמעלה, componentDidMount קורא ל-setupConnection שקורא this.state.serverUrl ו-this.props.roomId. זו הסיבה שcomponentDidUpdate בודק אם this.state.serverUrl וthis.props.roomId השתנו, ומאפס את החיבור אם כן. אם ההיגיון componentDidUpdate שלך חסר או לא מטפל בשינויים בכל props וstate הרלוונטיים, תקן זאת תחילה.

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

import { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);

// ...
}

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

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

export default function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [roomId, serverUrl]);

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>Welcome to the {roomId} room!</h1>
    </>
  );
}

Note

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


העברת רכיב עם הקשר ממחלקה לפונקציה

בדוגמה זו, רכיבי הכיתה Panel וButton קוראים את הקשר מ-this.context:

import { createContext, Component } from 'react';

const ThemeContext = createContext(null);

class Panel extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'panel-' + theme;
    return (
      <section className={className}>
        <h1>{this.props.title}</h1>
        {this.props.children}
      </section>
    );    
  }
}

class Button extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {this.props.children}
      </button>
    );
  }
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

כאשר אתה ממיר אותם לרכיבי פונקציה, החלף את this.context בקריאות useContext:

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}