Skip to content

Commit 672e859

Browse files
Veekas Shrivastavagaearon
authored andcommitted
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
1 parent 29287f0 commit 672e859

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,27 @@ describe('ReactComponentLifeCycle', () => {
198198
}).not.toThrow();
199199
});
200200

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+
201222
it('should not allow update state inside of getInitialState', () => {
202223
class StatefulComponent extends React.Component {
203224
constructor(props, context) {

packages/react-reconciler/src/ReactFiberClassComponent.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ let didWarnAboutLegacyLifecyclesAndDerivedState;
6464
let didWarnAboutUndefinedDerivedState;
6565
let warnOnUndefinedDerivedState;
6666
let warnOnInvalidCallback;
67+
let didWarnAboutDirectlyAssigningPropsToState;
6768

6869
if (__DEV__) {
6970
didWarnAboutStateAssignmentForComponent = new Set();
7071
didWarnAboutUninitializedState = new Set();
7172
didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set();
7273
didWarnAboutLegacyLifecyclesAndDerivedState = new Set();
74+
didWarnAboutDirectlyAssigningPropsToState = new Set();
7375
didWarnAboutUndefinedDerivedState = new Set();
7476

7577
const didWarnOnInvalidCallback = new Set();
@@ -674,6 +676,20 @@ function mountClassInstance(
674676
instance.context = getMaskedContext(workInProgress, unmaskedContext);
675677

676678
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+
677693
if (workInProgress.mode & StrictMode) {
678694
ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
679695
workInProgress,

0 commit comments

Comments
 (0)