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');