diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index 0d635439710e..52a6346ffbfa 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -802,16 +802,6 @@ export default function( ); newState = workInProgress.memoizedState; } - - if (typeof getDerivedStateFromProps === 'function') { - applyDerivedStateFromProps( - workInProgress, - getDerivedStateFromProps, - newProps, - ); - newState = workInProgress.memoizedState; - } - if ( oldProps === newProps && oldState === newState && @@ -829,6 +819,15 @@ export default function( return false; } + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + newProps, + ); + newState = workInProgress.memoizedState; + } + const shouldUpdate = checkShouldComponentUpdate( workInProgress, oldProps, @@ -937,17 +936,6 @@ export default function( newState = workInProgress.memoizedState; } - if (typeof getDerivedStateFromProps === 'function') { - if (fireGetDerivedStateFromPropsOnStateUpdates || oldProps !== newProps) { - applyDerivedStateFromProps( - workInProgress, - getDerivedStateFromProps, - newProps, - ); - newState = workInProgress.memoizedState; - } - } - if ( oldProps === newProps && oldState === newState && @@ -978,6 +966,17 @@ export default function( return false; } + if (typeof getDerivedStateFromProps === 'function') { + if (fireGetDerivedStateFromPropsOnStateUpdates || oldProps !== newProps) { + applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + newProps, + ); + newState = workInProgress.memoizedState; + } + } + const shouldUpdate = checkShouldComponentUpdate( workInProgress, oldProps, diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js index 20df85d4046a..a8289b113d69 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js @@ -1464,6 +1464,39 @@ describe('ReactIncremental', () => { expect(instance.state).toEqual({foo: 'foo'}); }); + it('does not call getDerivedStateFromProps if neither state nor props have changed', () => { + class Parent extends React.Component { + state = {parentRenders: 0}; + static getDerivedStateFromProps(props, prevState) { + ReactNoop.yield('getDerivedStateFromProps'); + return prevState.parentRenders + 1; + } + render() { + ReactNoop.yield('Parent'); + return ; + } + } + + class Child extends React.Component { + render() { + ReactNoop.yield('Child'); + return this.props.parentRenders; + } + } + + const child = React.createRef(null); + ReactNoop.render(); + expect(ReactNoop.flush()).toEqual([ + 'getDerivedStateFromProps', + 'Parent', + 'Child', + ]); + + // Schedule an update on the child. The parent should not re-render. + child.current.setState({}); + expect(ReactNoop.flush()).toEqual(['Child']); + }); + it('does not call getDerivedStateFromProps for state-only updates if feature flag is disabled', () => { jest.resetModules(); ReactFeatureFlags = require('shared/ReactFeatureFlags');