Skip to content

Commit 47f92b9

Browse files
authored
Merge pull request #8658 from acdlite/nullupdatetest
Should not re-render as the result of a null state update
2 parents d658ee8 + 2af6d7a commit 47f92b9

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

scripts/fiber/tests-passing.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1579,6 +1579,7 @@ src/renderers/shared/shared/__tests__/ReactUpdates-test.js
15791579
* unmounts and remounts a root in the same batch
15801580
* handles reentrant mounting in synchronous mode
15811581
* mounts and unmounts are sync even in a batch
1582+
* does not re-render if state update is null
15821583

15831584
src/renderers/shared/shared/__tests__/refs-destruction-test.js
15841585
* should remove refs when destroying the parent

src/renderers/shared/shared/__tests__/ReactUpdates-test.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313

1414
var React;
1515
var ReactDOM;
16-
var ReactDOMFeatureFlags;
1716
var ReactTestUtils;
1817
var ReactUpdates;
18+
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
1919

2020
describe('ReactUpdates', () => {
2121
beforeEach(() => {
@@ -1153,4 +1153,23 @@ describe('ReactUpdates', () => {
11531153
done();
11541154
});
11551155
});
1156+
1157+
it('does not re-render if state update is null', () => {
1158+
let container = document.createElement('div');
1159+
1160+
let instance;
1161+
let ops = [];
1162+
class Foo extends React.Component {
1163+
render() {
1164+
instance = this;
1165+
ops.push('render');
1166+
return <div />;
1167+
}
1168+
}
1169+
ReactDOM.render(<Foo />, container);
1170+
1171+
ops = [];
1172+
instance.setState(() => null);
1173+
expect(ops).toEqual([]);
1174+
});
11561175
});

src/renderers/shared/stack/reconciler/ReactCompositeComponent.js

+15-8
Original file line numberDiff line numberDiff line change
@@ -867,8 +867,9 @@ var ReactCompositeComponent = {
867867

868868
var nextState = this._processPendingState(nextProps, nextContext);
869869
var shouldUpdate = true;
870-
871870
if (!this._pendingForceUpdate) {
871+
var prevState = inst.state;
872+
shouldUpdate = willReceive || nextState !== prevState;
872873
if (inst.shouldComponentUpdate) {
873874
if (__DEV__) {
874875
shouldUpdate = measureLifeCyclePerf(
@@ -944,15 +945,21 @@ var ReactCompositeComponent = {
944945
return queue[0];
945946
}
946947

947-
var nextState = Object.assign({}, replace ? queue[0] : inst.state);
948+
var nextState = replace ? queue[0] : inst.state;
949+
var dontMutate = true;
948950
for (var i = replace ? 1 : 0; i < queue.length; i++) {
949951
var partial = queue[i];
950-
Object.assign(
951-
nextState,
952-
typeof partial === 'function' ?
953-
partial.call(inst, nextState, props, context) :
954-
partial
955-
);
952+
let partialState = typeof partial === 'function' ?
953+
partial.call(inst, nextState, props, context) :
954+
partial;
955+
if (partialState) {
956+
if (dontMutate) {
957+
dontMutate = false;
958+
nextState = Object.assign({}, nextState, partialState);
959+
} else {
960+
Object.assign(nextState, partialState);
961+
}
962+
}
956963
}
957964

958965
return nextState;

0 commit comments

Comments
 (0)