Skip to content

Commit 7a833da

Browse files
authored
setState() in componentDidMount() should flush synchronously even with createBatch() (#12466)
* Add a failing test for setState in cDM during batch.commit() * Copy pasta * Flush all follow-up Sync work on the committed batch * Nit: Use performSyncWork Call performSyncWork right after flushing the batch. Does effectively the same thing by reusing the existing function. Also added some comments. * Delete accidentally duplicated test
1 parent c44665e commit 7a833da

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

packages/react-dom/src/__tests__/ReactDOMRoot-test.internal.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,46 @@ describe('ReactDOMRoot', () => {
185185
expect(container.textContent).toEqual('Hi');
186186
});
187187

188+
it('applies setState in componentDidMount synchronously in a batch', done => {
189+
class App extends React.Component {
190+
state = {mounted: false};
191+
componentDidMount() {
192+
this.setState({
193+
mounted: true,
194+
});
195+
}
196+
render() {
197+
return this.state.mounted ? 'Hi' : 'Bye';
198+
}
199+
}
200+
201+
const root = ReactDOM.createRoot(container);
202+
const batch = root.createBatch();
203+
batch.render(
204+
<AsyncMode>
205+
<App />
206+
</AsyncMode>,
207+
);
208+
209+
flush();
210+
211+
// Hasn't updated yet
212+
expect(container.textContent).toEqual('');
213+
214+
let ops = [];
215+
batch.then(() => {
216+
// Still hasn't updated
217+
ops.push(container.textContent);
218+
219+
// Should synchronously commit
220+
batch.commit();
221+
ops.push(container.textContent);
222+
223+
expect(ops).toEqual(['', 'Hi']);
224+
done();
225+
});
226+
});
227+
188228
it('does not restart a completed batch when committing if there were no intervening updates', () => {
189229
let ops = [];
190230
function Foo(props) {

packages/react-reconciler/src/ReactFiberScheduler.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,15 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
11691169
interruptedBy = fiber;
11701170
resetStack();
11711171
}
1172-
if (nextRoot !== root || !isWorking) {
1172+
if (
1173+
// If we're in the render phase, we don't need to schedule this root
1174+
// for an update, because we'll do it before we exit...
1175+
!isWorking ||
1176+
isCommitting ||
1177+
// ...unless this is a different root than the one we're rendering.
1178+
nextRoot !== root
1179+
) {
1180+
// Add this root to the root schedule.
11731181
requestWork(root, expirationTime);
11741182
}
11751183
if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
@@ -1500,6 +1508,8 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
15001508
nextFlushedRoot = root;
15011509
nextFlushedExpirationTime = expirationTime;
15021510
performWorkOnRoot(root, expirationTime, false);
1511+
// Flush any sync work that was scheduled by lifecycles
1512+
performSyncWork();
15031513
finishRendering();
15041514
}
15051515

0 commit comments

Comments
 (0)