Handle errors thrown in gDSFP of a module-style context provider (#13269)
Context should be pushed before calling any user code, so if it errors the stack unwinds correctly.
Andrew Clark committed
Jul 25, 2018 at 14:22 UTC
bc1ea9cd96c81467c574b134349eafc303835d0e
2 files changed
+27
-4
packages/react-reconciler/src/ReactFiberBeginWork.js
+5
-4
@@ -618,6 +618,11 @@ function mountIndeterminateComponent(
618
// Proceed under the assumption that this is a class instance
619
workInProgress.tag = ClassComponent;
620
621
+ // Push context providers early to prevent context stack mismatches.
622
+ // During mounting we don't know the child context yet as the instance doesn't exist.
623
+ // We will invalidate the child context in finishClassComponent() right after rendering.
624
+ const hasContext = pushLegacyContextProvider(workInProgress);
625
+
626
workInProgress.memoizedState =
627
value.state !== null && value.state !== undefined ? value.state : null;
628
@@ -630,10 +635,6 @@ function mountIndeterminateComponent(
635
);
636
}
637
633
- // Push context providers early to prevent context stack mismatches.
634
- // During mounting we don't know the child context yet as the instance doesn't exist.
635
- // We will invalidate the child context in finishClassComponent() right after rendering.
636
- const hasContext = pushLegacyContextProvider(workInProgress);
638
adoptClassInstance(workInProgress, value);
639
mountClassInstance(workInProgress, renderExpirationTime);
640
return finishClassComponent(
packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
+22
@@ -1469,4 +1469,26 @@ describe('ReactIncrementalErrorHandling', () => {
1469
ReactNoop.flushDeferredPri();
1470
expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello')]);
1471
});
1472
+
1473
+ it('handles error thrown inside getDerivedStateFromProps of a module-style context provider', () => {
1474
+ function Provider() {
1475
+ return {
1476
+ getChildContext() {
1477
+ return {foo: 'bar'};
1478
+ },
1479
+ render() {
1480
+ return 'Hi';
1481
+ },
1482
+ };
1483
+ }
1484
+ Provider.childContextTypes = {
1485
+ x: () => {},
1486
+ };
1487
+ Provider.getDerivedStateFromProps = () => {
1488
+ throw new Error('Oops!');
1489
+ };
1490
+
1491
+ ReactNoop.render(<Provider />);
1492
+ expect(() => ReactNoop.flush()).toThrow('Oops!');
1493
+ });
1494
});