Add warning to prevent setting this.state to this.props referentially (#11658)
* add test to warn if setting this.state to this.props referentially * Avoid an extra check
Veekas Shrivastava committed
Aug 28, 2018 at 09:17 UTC
672e859d311536ddf5f09fb47dcb84007703aa65
2 files changed
+37
packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
+21
@@ -198,6 +198,27 @@ describe('ReactComponentLifeCycle', () => {
198
}).not.toThrow();
199
});
200
201
+ it("warns if setting 'this.state = props'", () => {
202
+ class StatefulComponent extends React.Component {
203
+ constructor(props, context) {
204
+ super(props, context);
205
+ this.state = props;
206
+ }
207
+ render() {
208
+ return <div />;
209
+ }
210
+ }
211
+
212
+ expect(() => {
213
+ ReactTestUtils.renderIntoDocument(<StatefulComponent />);
214
+ }).toWarnDev(
215
+ 'StatefulComponent: It is not recommended to assign props directly to state ' +
216
+ "because updates to props won't be reflected in state. " +
217
+ 'In most cases, it is better to use props directly.',
218
+ {withoutStack: true},
219
+ );
220
+ });
221
+
222
it('should not allow update state inside of getInitialState', () => {
223
class StatefulComponent extends React.Component {
224
constructor(props, context) {
packages/react-reconciler/src/ReactFiberClassComponent.js
+16
@@ -64,12 +64,14 @@ let didWarnAboutLegacyLifecyclesAndDerivedState;
64
let didWarnAboutUndefinedDerivedState;
65
let warnOnUndefinedDerivedState;
66
let warnOnInvalidCallback;
67
+let didWarnAboutDirectlyAssigningPropsToState;
68
69
if (__DEV__) {
70
didWarnAboutStateAssignmentForComponent = new Set();
71
didWarnAboutUninitializedState = new Set();
72
didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set();
73
didWarnAboutLegacyLifecyclesAndDerivedState = new Set();
74
+ didWarnAboutDirectlyAssigningPropsToState = new Set();
75
didWarnAboutUndefinedDerivedState = new Set();
76
77
const didWarnOnInvalidCallback = new Set();
@@ -674,6 +676,20 @@ function mountClassInstance(
676
instance.context = getMaskedContext(workInProgress, unmaskedContext);
677
678
if (__DEV__) {
679
+ if (instance.state === newProps) {
680
+ const componentName = getComponentName(ctor) || 'Component';
681
+ if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) {
682
+ didWarnAboutDirectlyAssigningPropsToState.add(componentName);
683
+ warningWithoutStack(
684
+ false,
685
+ '%s: It is not recommended to assign props directly to state ' +
686
+ "because updates to props won't be reflected in state. " +
687
+ 'In most cases, it is better to use props directly.',
688
+ componentName,
689
+ );
690
+ }
691
+ }
692
+
693
if (workInProgress.mode & StrictMode) {
694
ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
695
workInProgress,