diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index 389dd4ca4fe..f6d8e192d4b 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -364,6 +364,22 @@ export default function( name, name, ); + const noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== 'function'; + warning( + noInstanceGetDerivedStateFromProps, + '%s: getDerivedStateFromProps() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.', + name, + ); + const noInstanceGetDerivedStateFromCatch = + typeof instance.getDerivedStateFromCatch !== 'function'; + warning( + noInstanceGetDerivedStateFromCatch, + '%s: getDerivedStateFromCatch() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.', + name, + ); const state = instance.state; if (state && (typeof state !== 'object' || isArray(state))) { warning(false, '%s.state: must be set to an object or null', name); diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index 2f0fa46455c..892a96d0475 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -118,6 +118,28 @@ describe 'ReactCoffeeScriptClass', -> test React.createElement(Foo, foo: 'foo'), 'DIV', 'foo bar' undefined + it 'warns if getDerivedStateFromProps is not static', -> + class Foo extends React.Component + render: -> + div() + getDerivedStateFromProps: -> + {} + expect(-> + ReactDOM.render(React.createElement(Foo, foo: 'foo'), container) + ).toWarnDev 'Foo: getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.', + undefined + + it 'warns if getDerivedStateFromCatch is not static', -> + class Foo extends React.Component + render: -> + div() + getDerivedStateFromCatch: -> + {} + expect(-> + ReactDOM.render(React.createElement(Foo, foo: 'foo'), container) + ).toWarnDev 'Foo: getDerivedStateFromCatch() is defined as an instance method and will be ignored. Instead, declare it as a static method.', + undefined + it 'warns if state not initialized before static getDerivedStateFromProps', -> class Foo extends React.Component render: -> diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 793a5153f87..c48d7244a4c 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -128,6 +128,36 @@ describe('ReactES6Class', () => { test(, 'DIV', 'foo bar'); }); + it('warns if getDerivedStateFromProps is not static', () => { + class Foo extends React.Component { + getDerivedStateFromProps() { + return {}; + } + render() { + return
; + } + } + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Foo: getDerivedStateFromProps() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.', + ); + }); + + it('warns if getDerivedStateFromCatch is not static', () => { + class Foo extends React.Component { + getDerivedStateFromCatch() { + return {}; + } + render() { + return
; + } + } + expect(() => ReactDOM.render(, container)).toWarnDev( + 'Foo: getDerivedStateFromCatch() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.', + ); + }); + it('warns if state not initialized before static getDerivedStateFromProps', () => { class Foo extends React.Component { static getDerivedStateFromProps(nextProps, prevState) { diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index 68313fd68da..b51b89cc254 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -378,6 +378,40 @@ describe('ReactTypeScriptClass', function() { test(React.createElement(Foo, {foo: 'foo'}), 'DIV', 'foo bar'); }); + it('warns if getDerivedStateFromProps is not static', function() { + class Foo extends React.Component { + getDerivedStateFromProps() { + return {}; + } + render() { + return React.createElement('div', {}); + } + } + expect(function() { + ReactDOM.render(React.createElement(Foo, {foo: 'foo'}), container); + }).toWarnDev( + 'Foo: getDerivedStateFromProps() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.' + ); + }); + + it('warns if getDerivedStateFromCatch is not static', function() { + class Foo extends React.Component { + getDerivedStateFromCatch() { + return {}; + } + render() { + return React.createElement('div'); + } + } + expect(function() { + ReactDOM.render(React.createElement(Foo, {foo: 'foo'}), container); + }).toWarnDev( + 'Foo: getDerivedStateFromCatch() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.' + ); + }); + it('warns if state not initialized before static getDerivedStateFromProps', function() { class Foo extends React.Component { static getDerivedStateFromProps(nextProps, prevState) { diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.js b/packages/react/src/__tests__/createReactClassIntegration-test.js index c567b4fd853..fc5fb333ca5 100644 --- a/packages/react/src/__tests__/createReactClassIntegration-test.js +++ b/packages/react/src/__tests__/createReactClassIntegration-test.js @@ -433,6 +433,40 @@ describe('create-react-class-integration', () => { expect(instance.state.foo).toBe('bar'); }); + it('warns if getDerivedStateFromProps is not static', () => { + const Foo = createReactClass({ + getDerivedStateFromProps() { + return {}; + }, + render() { + return
; + }, + }); + expect(() => + ReactDOM.render(, document.createElement('div')), + ).toWarnDev( + 'Component: getDerivedStateFromProps() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.', + ); + }); + + it('warns if getDerivedStateFromCatch is not static', () => { + const Foo = createReactClass({ + getDerivedStateFromCatch() { + return {}; + }, + render() { + return
; + }, + }); + expect(() => + ReactDOM.render(, document.createElement('div')), + ).toWarnDev( + 'Component: getDerivedStateFromCatch() is defined as an instance method ' + + 'and will be ignored. Instead, declare it as a static method.', + ); + }); + it('should warn if state is not properly initialized before getDerivedStateFromProps', () => { const Component = createReactClass({ statics: {