diff --git a/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js index 6f9cf52787e13..3eea121d65b36 100644 --- a/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js @@ -201,32 +201,32 @@ describe('React hooks DevTools integration', () => { if (__DEV__) { // First render was locked expect(renderer.toJSON().children).toEqual(['Loading']); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Loading']); // Release the lock setSuspenseHandler(() => false); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); // Lock again setSuspenseHandler(() => true); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Loading']); // Release the lock again setSuspenseHandler(() => false); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); // Ensure it checks specific fibers. setSuspenseHandler(f => f === fiber || f === fiber.alternate); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Loading']); setSuspenseHandler(f => f !== fiber && f !== fiber.alternate); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); } else { expect(renderer.toJSON().children).toEqual(['Done']); @@ -259,33 +259,33 @@ describe('React hooks DevTools integration', () => { if (__DEV__) { // First render was locked expect(renderer.toJSON().children).toEqual(['Loading']); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Loading']); // Release the lock setSuspenseHandler(() => false); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render Scheduler.unstable_flushAll(); expect(renderer.toJSON().children).toEqual(['Done']); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); // Lock again setSuspenseHandler(() => true); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Loading']); // Release the lock again setSuspenseHandler(() => false); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); // Ensure it checks specific fibers. setSuspenseHandler(f => f === fiber || f === fiber.alternate); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Loading']); setSuspenseHandler(f => f !== fiber && f !== fiber.alternate); - scheduleUpdate(fiber); // Re-render + act(() => scheduleUpdate(fiber)); // Re-render expect(renderer.toJSON().children).toEqual(['Done']); } else { expect(renderer.toJSON().children).toEqual(['Done']); diff --git a/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js b/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js index dd682d2def59f..c0617f9b56787 100644 --- a/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js @@ -281,4 +281,52 @@ 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); + const countRef = React.useRef(-1); + + React.useLayoutEffect(() => { + countRef.current = count; + target.current.onclick = () => { + setCount(countRef.current + 1); + // Now update again. If these updates are batched, then this should be + // a no-op, because we didn't re-render yet and `countRef` hasn't + // been mutated. + setCount(countRef.current + 1); + }; + }); + return