Skip to content

Commit

Permalink
Fix native event batching in concurrent mode
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Mar 15, 2021
1 parent f8979e0 commit 0120986
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,44 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
expect(container.textContent).toEqual('hovered');
});
});

// @gate experimental
it('should batch inside native events', async () => {
const root = ReactDOM.unstable_createRoot(container);

const target = React.createRef(null);
function Foo() {
const [count, setCount] = React.useState(0);

React.useEffect(() => {
Scheduler.unstable_yieldValue(count);
}, [count]);

React.useLayoutEffect(() => {
target.current.onclick = () => {
setCount(c => c + 1);
// Now update again, this should be batched.
setCount(c => c + 1);
};
});
return <div ref={target}>Count: {count}</div>;
}

await act(async () => {
root.render(<Foo />);
});
expect(Scheduler).toHaveYielded([0]);
expect(container.textContent).toEqual('Count: 0');

// Ignore act warning. We can't use act because it forces batched updates.
spyOnDev(console, 'error');

const pressEvent = document.createEvent('Event');
pressEvent.initEvent('click', true, true);
dispatchAndSetCurrentEvent(target.current, pressEvent);

expect(Scheduler).toHaveYielded([]);
expect(container.textContent).toEqual('Count: 2');
expect(Scheduler).toFlushAndYield([2]);
});
});
5 changes: 4 additions & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,10 @@ export function scheduleUpdateOnFiber(
} else {
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, lane);
if (executionContext === NoContext) {
if (
(fiber.mode & ConcurrentMode) === NoMode &&
executionContext === NoContext
) {
// Flush the synchronous work now, unless we're already working or inside
// a batch. This is intentionally inside scheduleUpdateOnFiber instead of
// scheduleCallbackForFiber to preserve the ability to schedule a callback
Expand Down
5 changes: 4 additions & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,10 @@ export function scheduleUpdateOnFiber(
} else {
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, lane);
if (executionContext === NoContext) {
if (
(fiber.mode & ConcurrentMode) === NoMode &&
executionContext === NoContext
) {
// Flush the synchronous work now, unless we're already working or inside
// a batch. This is intentionally inside scheduleUpdateOnFiber instead of
// scheduleCallbackForFiber to preserve the ability to schedule a callback
Expand Down

0 comments on commit 0120986

Please sign in to comment.