تفاعل مع التحديثات المجمعة

كيفية الجمع بين تحديثات الحالة في مكالمة واحدة

تحديثات مجمعة في React.js

أنت تعلم بالفعل أنه كلما قمت بتحديث حالة أحد المكونات ، ستكتشف خوارزمية الاختلاف في React التغييرات في DOM الظاهري وستعرض المكون الخاص بك في DOM الحقيقي. ولكن هل يحدث هذا حقًا لكل تحديث حالة؟ أم أن React توفر طريقة لتجميع تلك التحديثات ، بحيث يتم دمج طفرات الحالة المتعددة في استدعاء تصيير واحد؟

تسمح الأحداث الاصطناعية بتحديثات الدُفعات

توفر React 17 والإصدارات الأدنى آلية لتجميع هذه التحديثات. لست مضطرًا للتفكير في الأمر كثيرًا أثناء البرمجة ، ولكن معرفة كيف يمكن لـ 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
}

الاقتراحات

ذات صلة

ملحق

اللغات