Fix bug when fatal error is thrown as a result of `batch.commit` (#12480)
Fixes #12474
Andrew Clark committed
Mar 28, 2018 at 18:18 UTC
c44665e83278becfe7a3afdf788789536d63387b
2 files changed
+18
-1
packages/react-dom/src/__tests__/ReactDOMRoot-test.internal.js
+10
@@ -320,4 +320,14 @@ describe('ReactDOMRoot', () => {
320
flush();
321
expect(container.textContent).toEqual('1');
322
});
323
+
324
+ it('handles fatal errors triggered by batch.commit()', () => {
325
+ const root = ReactDOM.createRoot(container);
326
+ const batch = root.createBatch();
327
+ const InvalidType = undefined;
328
+ expect(() => batch.render(<InvalidType />)).toWarnDev([
329
+ 'React.createElement: type is invalid',
330
+ ]);
331
+ expect(() => batch.commit()).toThrow('Element type is invalid');
332
+ });
333
});
packages/react-reconciler/src/ReactFiberScheduler.js
+8
-1
@@ -932,7 +932,12 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
932
const sourceFiber: Fiber = nextUnitOfWork;
933
let returnFiber = sourceFiber.return;
934
if (returnFiber === null) {
935
- // This is a fatal error.
935
+ // This is the root. The root could capture its own errors. However,
936
+ // we don't know if it errors before or after we pushed the host
937
+ // context. This information is needed to avoid a stack mismatch.
938
+ // Because we're not sure, treat this as a fatal error. We could track
939
+ // which phase it fails in, but doesn't seem worth it. At least
940
+ // for now.
941
didFatal = true;
942
onUncaughtError(thrownValue);
943
break;
@@ -1492,6 +1497,8 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
1497
// Perform work on root as if the given expiration time is the current time.
1498
// This has the effect of synchronously flushing all work up to and
1499
// including the given time.
1500
+ nextFlushedRoot = root;
1501
+ nextFlushedExpirationTime = expirationTime;
1502
performWorkOnRoot(root, expirationTime, false);
1503
finishRendering();
1504
}