From b179bae0ae3a9d80bfbe440c8861786b7f928ce1 Mon Sep 17 00:00:00 2001 From: Felix Wu Date: Fri, 3 Aug 2018 17:09:57 +0200 Subject: [PATCH] Enhance get derived state from props state warning - #12670 (#13317) * Enhance warning message for missing state with getDerivedStateFromProps * Adapt tests * style fix * Tweak da message * Fix test --- .../src/__tests__/ReactComponentLifeCycle-test.js | 6 ++++-- .../src/__tests__/ReactDOMServerLifecycles-test.js | 6 ++++-- .../react-dom/src/server/ReactPartialRenderer.js | 7 +++++-- .../react-reconciler/src/ReactFiberClassComponent.js | 7 +++++-- .../src/__tests__/ReactCoffeeScriptClass-test.coffee | 7 ++++++- packages/react/src/__tests__/ReactES6Class-test.js | 6 ++++-- .../react/src/__tests__/ReactTypeScriptClass-test.ts | 6 ++++-- .../__tests__/createReactClassIntegration-test.js | 12 +++++++++--- 8 files changed, 41 insertions(+), 16 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js index 496e003a781d5..cde3ab7a4f4f3 100644 --- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js +++ b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js @@ -1003,8 +1003,10 @@ describe('ReactComponentLifeCycle', () => { const div = document.createElement('div'); expect(() => ReactDOM.render(, div)).toWarnDev( - 'MyComponent: Did not properly initialize state during construction. ' + - 'Expected state to be an object, but it was undefined.', + '`MyComponent` uses `getDerivedStateFromProps` but its initial state is ' + + 'undefined. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `MyComponent`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', {withoutStack: true}, ); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js b/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js index b0a4a29593b92..11c99ce07aacc 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerLifecycles-test.js @@ -201,8 +201,10 @@ describe('ReactDOMServerLifecycles', () => { } expect(() => ReactDOMServer.renderToString()).toWarnDev( - 'Component: Did not properly initialize state during construction. ' + - 'Expected state to be an object, but it was undefined.', + '`Component` uses `getDerivedStateFromProps` but its initial state is ' + + 'undefined. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `Component`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', {withoutStack: true}, ); diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index 19bf9c94a7f23..02487cafa5398 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -476,10 +476,13 @@ function resolve( if (!didWarnAboutUninitializedState[componentName]) { warningWithoutStack( false, - '%s: Did not properly initialize state during construction. ' + - 'Expected state to be an object, but it was %s.', + '`%s` uses `getDerivedStateFromProps` but its initial state is ' + + '%s. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `%s`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', componentName, inst.state === null ? 'null' : 'undefined', + componentName, ); didWarnAboutUninitializedState[componentName] = true; } diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index cc2103fe22f8e..60ee9c2ac748e 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -505,10 +505,13 @@ function constructClassInstance( didWarnAboutUninitializedState.add(componentName); warningWithoutStack( false, - '%s: Did not properly initialize state during construction. ' + - 'Expected state to be an object, but it was %s.', + '`%s` uses `getDerivedStateFromProps` but its initial state is ' + + '%s. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `%s`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', componentName, instance.state === null ? 'null' : 'undefined', + componentName, ); } } diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index ed49ba0072ce4..4043188709899 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -163,7 +163,12 @@ describe 'ReactCoffeeScriptClass', -> } expect(-> ReactDOM.render(React.createElement(Foo, foo: 'foo'), container) - ).toWarnDev 'Foo: Did not properly initialize state during construction. Expected state to be an object, but it was undefined.', {withoutStack: true} + ).toWarnDev ( + '`Foo` uses `getDerivedStateFromProps` but its initial state is ' + + 'undefined. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `Foo`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.' + ), {withoutStack: true} undefined it 'updates initial state with values returned by static getDerivedStateFromProps', -> diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 39da681bd6bdd..0b2ade96afec9 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -190,8 +190,10 @@ describe('ReactES6Class', () => { } } expect(() => ReactDOM.render(, container)).toWarnDev( - 'Foo: Did not properly initialize state during construction. ' + - 'Expected state to be an object, but it was undefined.', + '`Foo` uses `getDerivedStateFromProps` but its initial state is ' + + 'undefined. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `Foo`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', {withoutStack: true}, ); }); diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index 443259373fef1..ae72ca2068d4a 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -448,8 +448,10 @@ describe('ReactTypeScriptClass', function() { expect(function() { ReactDOM.render(React.createElement(Foo, {foo: 'foo'}), container); }).toWarnDev( - 'Foo: Did not properly initialize state during construction. ' + - 'Expected state to be an object, but it was undefined.', + '`Foo` uses `getDerivedStateFromProps` but its initial state is ' + + 'undefined. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `Foo`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', {withoutStack: true} ); }); diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.js b/packages/react/src/__tests__/createReactClassIntegration-test.js index 255b7602cbf76..bd7aca0d228cd 100644 --- a/packages/react/src/__tests__/createReactClassIntegration-test.js +++ b/packages/react/src/__tests__/createReactClassIntegration-test.js @@ -510,9 +510,15 @@ describe('create-react-class-integration', () => { }); expect(() => ReactDOM.render(, document.createElement('div')), - ).toWarnDev('Did not properly initialize state during construction.', { - withoutStack: true, - }); + ).toWarnDev( + '`Component` uses `getDerivedStateFromProps` but its initial state is ' + + 'null. This is not recommended. Instead, define the initial state by ' + + 'assigning an object to `this.state` in the constructor of `Component`. ' + + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', + { + withoutStack: true, + }, + ); }); it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', () => {