Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add errorInfo and prevState parameters to getDerivedStateFromError #13986

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/react-reconciler/src/ReactFiberThrow.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,21 @@ function createClassErrorUpdate(
): Update<mixed> {
const update = createUpdate(expirationTime, null);
update.tag = CaptureUpdate;
const inst = fiber.stateNode;
const getDerivedStateFromError = fiber.type.getDerivedStateFromError;
if (typeof getDerivedStateFromError === 'function') {
const error = errorInfo.value;
const stack = errorInfo.stack;
const errorPartialInfo = {
componentStack: stack !== null ? stack : '',
};
const state = inst !== null ? inst.state : null;
update.payload = () => {
logError(fiber, errorInfo);
return getDerivedStateFromError(error);
return getDerivedStateFromError(error, errorPartialInfo, state);
};
}

const inst = fiber.stateNode;
if (inst !== null && typeof inst.componentDidCatch === 'function') {
update.callback = function callback() {
if (__DEV__) {
Expand All @@ -115,9 +120,10 @@ function createClassErrorUpdate(
}
const error = errorInfo.value;
const stack = errorInfo.stack;
this.componentDidCatch(error, {
const errorPartialInfo = {
componentStack: stack !== null ? stack : '',
});
};
this.componentDidCatch(error, errorPartialInfo);
if (__DEV__) {
if (typeof getDerivedStateFromError !== 'function') {
// If componentDidCatch is the only error boundary method defined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1600,16 +1600,23 @@ describe('ReactIncrementalErrorHandling', () => {
]);
});

it('does not provide component stack to the error boundary with getDerivedStateFromError', () => {
it('provides component stack and state to the error boundary with getDerivedStateFromError', () => {
class ErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error, errorInfo) {
expect(errorInfo).toBeUndefined();
return {error};
state = {error: null, foo: 'foo'};
static getDerivedStateFromError(error, errorInfo, prevState) {
expect(error.message).toBe('Hello');
expect(prevState.foo).toBe('foo');
return {error, errorInfo, foo: prevState.foo.toUpperCase()};
}
render() {
if (this.state.error) {
return <span prop={`Caught an error: ${this.state.error.message}`} />;
if (this.state.errorInfo) {
return (
<span
prop={`Caught an error:${normalizeCodeLocInfo(
this.state.errorInfo.componentStack,
)}. Derived foo: ${this.state.foo}.`}
/>
);
}
return this.props.children;
}
Expand All @@ -1625,7 +1632,18 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>,
);
expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello')]);
expect(ReactNoop.getChildren()).toEqual([
span(
'Caught an error:\n' +
(__DEV__
? ' in BrokenRender (at **)\n'
: ' in BrokenRender\n') +
(__DEV__
? ' in ErrorBoundary (at **).'
: ' in ErrorBoundary.') +
' Derived foo: FOO.',
),
]);
});

it('handles error thrown inside getDerivedStateFromProps of a module-style context provider', () => {
Expand Down