React Batched Updates

כיצד לשלב עדכוני מצב בשיחת עיבוד אחת

עדכונים אצווה של React.js

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

אירועים סינתטיים מאפשרים עדכוני קבוצות

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

הנה מה שקורה.

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

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

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

function Component() {
  const [id, setId] = useState(0);
  const [date, setDate] = useState(new Date());
  const [random, setRandom] = useState(Math.random());

  // A lame callback, but it's just for
  // the demo. Note that clicking on the
  // button will only lead to a single
  // re-render!
  //
  // This is b/c the callback is provided to
  // 'onClick', a synthetic event.
  const onButtonClick = () => {
    setDate(new Date());
    setId(prevId => prevId + 1);
  }
  
  console.log("Render:", id, date);

  return (
    <div>
      <button 
        onClick={onButtonClick}>
        Update state
      </button>
    </div>
  );
}
//
// Almost the same as the previous
// example, but this time w/o
// a batched upate call.
//

function Component() {
  const [id, setId] = useState(0);
  const [date, setDate] = useState(new Date());
  const [random, setRandom] = useState(Math.random());

  // No batching, as the state
  // mutations happend inside
  // a setTimeout - even though
  // the timeout is inside a 
  // synthetic event.
  const onButtonClick = () => {
    setTimeout(() => {
      setDate(new Date());
      setId(prevId => prevId + 1);
    }, 0);
  }
  
  console.log("Render:", id, date);

  return (
    <div>
      <button 
        onClick={onButtonClick}>
        Update state
      </button>
    </div>
  );
}

עדכונים מרובים עבור React 18 ואילך

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

  • פסק זמן
  • הבטחות
  • מטפלים לאירועים מקומיים

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

הימנעות מעדכונים אצווה ב- React 18 ואילך

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

//  
// This example is almost
// 1:1 from Dan Abramov's
// example.
//
// Use 'flushSync' from the
// 'react-dom'-package.
import { flushSync } from 'react-dom'; 

function handleClick() {
  flushSync(() => {
    setId(prevId => prevId + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setDate(new Date());
  });
  // React has updated the DOM by now
}