main
js 64 lines 2.22 KB
Raw
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 flushSyncWork,
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 // @TODO Should move to flushSyncWork once legacy mode is removed but since this flushSync
40 // flushes passive effects we can't do this yet.
41 flushSyncWork();
42 restoreStateIfNeeded();
43 }
44 }
45
46 export function batchedUpdates(fn, a, b) {
47 if (isInsideEventHandler) {
48 // If we are currently inside another batch, we need to wait until it
49 // fully completes before restoring state.
50 return fn(a, b);
51 }
52 isInsideEventHandler = true;
53 try {
54 return batchedUpdatesImpl(fn, a, b);
55 } finally {
56 isInsideEventHandler = false;
57 finishEventHandler();
58 }
59 }
60
61 // TODO: Replace with flushSync
62 export function discreteUpdates(fn, a, b, c, d) {
63 return discreteUpdatesImpl(fn, a, b, c, d);
64 }