Skip to content

Commit 2c8a145

Browse files
authored
Fix ignored setState in Safari when iframe is touched (#24459)
1 parent 6266263 commit 2c8a145

File tree

3 files changed

+47
-12
lines changed

3 files changed

+47
-12
lines changed

packages/react-dom/src/__tests__/ReactDOMSafariMicrotaskBug-test.js

+35-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let act;
1616

1717
describe('ReactDOMSafariMicrotaskBug-test', () => {
1818
let container;
19-
let simulateSafariBug;
19+
let flushMicrotasksPrematurely;
2020

2121
beforeEach(() => {
2222
// In Safari, microtasks don't always run on clean stack.
@@ -27,9 +27,12 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
2727
window.queueMicrotask = function(cb) {
2828
queue.push(cb);
2929
};
30-
simulateSafariBug = function() {
31-
queue.forEach(cb => cb());
32-
queue = [];
30+
flushMicrotasksPrematurely = function() {
31+
while (queue.length > 0) {
32+
const prevQueue = queue;
33+
queue = [];
34+
prevQueue.forEach(cb => cb());
35+
}
3336
};
3437

3538
jest.resetModules();
@@ -45,7 +48,7 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
4548
document.body.removeChild(container);
4649
});
4750

48-
it('should be resilient to buggy queueMicrotask', async () => {
51+
it('should deal with premature microtask in commit phase', async () => {
4952
let ran = false;
5053
function Foo() {
5154
const [state, setState] = React.useState(0);
@@ -55,7 +58,7 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
5558
if (!ran) {
5659
ran = true;
5760
setState(1);
58-
simulateSafariBug();
61+
flushMicrotasksPrematurely();
5962
}
6063
}}>
6164
{state}
@@ -68,4 +71,30 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
6871
});
6972
expect(container.textContent).toBe('1');
7073
});
74+
75+
it('should deal with premature microtask in event handler', async () => {
76+
function Foo() {
77+
const [state, setState] = React.useState(0);
78+
return (
79+
<button
80+
onClick={() => {
81+
setState(1);
82+
flushMicrotasksPrematurely();
83+
}}>
84+
{state}
85+
</button>
86+
);
87+
}
88+
const root = ReactDOMClient.createRoot(container);
89+
await act(async () => {
90+
root.render(<Foo />);
91+
});
92+
expect(container.textContent).toBe('0');
93+
await act(async () => {
94+
container.firstChild.dispatchEvent(
95+
new MouseEvent('click', {bubbles: true}),
96+
);
97+
});
98+
expect(container.textContent).toBe('1');
99+
});
71100
});

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -835,9 +835,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
835835
// https://github.com/facebook/react/issues/22459
836836
// We don't support running callbacks in the middle of render
837837
// or commit so we need to check against that.
838-
if (executionContext === NoContext) {
839-
// It's only safe to do this conditionally because we always
840-
// check for pending work before we exit the task.
838+
if (
839+
(executionContext & (RenderContext | CommitContext)) ===
840+
NoContext
841+
) {
842+
// Note that this would still prematurely flush the callbacks
843+
// if this happens outside render or commit phase (e.g. in an event).
841844
flushSyncCallbacks();
842845
}
843846
});

packages/react-reconciler/src/ReactFiberWorkLoop.old.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -835,9 +835,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
835835
// https://github.com/facebook/react/issues/22459
836836
// We don't support running callbacks in the middle of render
837837
// or commit so we need to check against that.
838-
if (executionContext === NoContext) {
839-
// It's only safe to do this conditionally because we always
840-
// check for pending work before we exit the task.
838+
if (
839+
(executionContext & (RenderContext | CommitContext)) ===
840+
NoContext
841+
) {
842+
// Note that this would still prematurely flush the callbacks
843+
// if this happens outside render or commit phase (e.g. in an event).
841844
flushSyncCallbacks();
842845
}
843846
});

0 commit comments

Comments
 (0)