1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  */
    
  7. 
    
  8. import {
    
  9.   needsStateRestore,
    
  10.   restoreStateIfNeeded,
    
  11. } from './ReactDOMControlledComponent';
    
  12. 
    
  13. import {
    
  14.   batchedUpdates as batchedUpdatesImpl,
    
  15.   discreteUpdates as discreteUpdatesImpl,
    
  16.   flushSync as flushSyncImpl,
    
  17. } from 'react-reconciler/src/ReactFiberReconciler';
    
  18. 
    
  19. // Used as a way to call batchedUpdates when we don't have a reference to
    
  20. // the renderer. Such as when we're dispatching events or if third party
    
  21. // libraries need to call batchedUpdates. Eventually, this API will go away when
    
  22. // everything is batched by default. We'll then have a similar API to opt-out of
    
  23. // scheduled work and instead do synchronous work.
    
  24. 
    
  25. let isInsideEventHandler = false;
    
  26. 
    
  27. function finishEventHandler() {
    
  28.   // Here we wait until all updates have propagated, which is important
    
  29.   // when using controlled components within layers:
    
  30.   // https://github.com/facebook/react/issues/1698
    
  31.   // Then we restore state of any controlled component.
    
  32.   const controlledComponentsHavePendingUpdates = needsStateRestore();
    
  33.   if (controlledComponentsHavePendingUpdates) {
    
  34.     // If a controlled event was fired, we may need to restore the state of
    
  35.     // the DOM node back to the controlled value. This is necessary when React
    
  36.     // bails out of the update without touching the DOM.
    
  37.     // TODO: Restore state in the microtask, after the discrete updates flush,
    
  38.     // instead of early flushing them here.
    
  39.     flushSyncImpl();
    
  40.     restoreStateIfNeeded();
    
  41.   }
    
  42. }
    
  43. 
    
  44. export function batchedUpdates(fn, a, b) {
    
  45.   if (isInsideEventHandler) {
    
  46.     // If we are currently inside another batch, we need to wait until it
    
  47.     // fully completes before restoring state.
    
  48.     return fn(a, b);
    
  49.   }
    
  50.   isInsideEventHandler = true;
    
  51.   try {
    
  52.     return batchedUpdatesImpl(fn, a, b);
    
  53.   } finally {
    
  54.     isInsideEventHandler = false;
    
  55.     finishEventHandler();
    
  56.   }
    
  57. }
    
  58. 
    
  59. // TODO: Replace with flushSync
    
  60. export function discreteUpdates(fn, a, b, c, d) {
    
  61.   return discreteUpdatesImpl(fn, a, b, c, d);
    
  62. }