@samitouri / QOS-React-2 / commits / 36c2939372

Improve not-yet-mounted setState warning (#12531)

* Tweak not-yet-mounted setState warning * Add \n\n

Dan Abramov committed Apr 3, 2018 at 21:22 UTC 36c29393720157a3966ce1d50449a33a35bdf14c
3 files changed +65 -8
packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
+6 -4
@@ -214,10 +214,12 @@ describe('ReactComponentLifeCycle', () => {
214 expect(() => {
215 ReactTestUtils.renderIntoDocument(<StatefulComponent />);
216 }).toWarnDev(
217 - 'Warning: setState(...): Can only update a mounted or ' +
218 - 'mounting component. This usually means you called setState() on an ' +
219 - 'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
220 - 'StatefulComponent component.',
217 + "Warning: Can't call setState on a component that is not yet mounted. " +
218 + 'This is a no-op, but it might indicate a bug in your application.\n\n' +
219 + 'To fix, assign the initial state in the StatefulComponent constructor. ' +
220 + 'If the state needs to reflect an external data source, ' +
221 + 'you may also add a componentDidMount lifecycle hook to StatefulComponent ' +
222 + 'and call setState there if the external data has changed.',
223 );
224
225 // Check deduplication; (no extra warnings should be logged).
packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
+52
@@ -225,6 +225,58 @@ describe('ReactCompositeComponent', () => {
225 expect(inputProps.prop).not.toBeDefined();
226 });
227
228 + it('should warn about `forceUpdate` on not-yet-mounted components', () => {
229 + class MyComponent extends React.Component {
230 + constructor(props) {
231 + super(props);
232 + this.forceUpdate();
233 + }
234 + render() {
235 + return <div />;
236 + }
237 + }
238 +
239 + const container = document.createElement('div');
240 + expect(() => ReactDOM.render(<MyComponent />, container)).toWarnDev(
241 + "Warning: Can't call forceUpdate on a component that is not yet mounted. " +
242 + 'This is a no-op, but it might indicate a bug in your application.\n\n' +
243 + 'To fix, assign the initial state in the MyComponent constructor. ' +
244 + 'If the state needs to reflect an external data source, ' +
245 + 'you may also add a componentDidMount lifecycle hook to MyComponent ' +
246 + 'and call setState there if the external data has changed.',
247 + );
248 +
249 + // No additional warning should be recorded
250 + const container2 = document.createElement('div');
251 + ReactDOM.render(<MyComponent />, container2);
252 + });
253 +
254 + it('should warn about `setState` on not-yet-mounted components', () => {
255 + class MyComponent extends React.Component {
256 + constructor(props) {
257 + super(props);
258 + this.setState();
259 + }
260 + render() {
261 + return <div />;
262 + }
263 + }
264 +
265 + const container = document.createElement('div');
266 + expect(() => ReactDOM.render(<MyComponent />, container)).toWarnDev(
267 + "Warning: Can't call setState on a component that is not yet mounted. " +
268 + 'This is a no-op, but it might indicate a bug in your application.\n\n' +
269 + 'To fix, assign the initial state in the MyComponent constructor. ' +
270 + 'If the state needs to reflect an external data source, ' +
271 + 'you may also add a componentDidMount lifecycle hook to MyComponent ' +
272 + 'and call setState there if the external data has changed.',
273 + );
274 +
275 + // No additional warning should be recorded
276 + const container2 = document.createElement('div');
277 + ReactDOM.render(<MyComponent />, container2);
278 + });
279 +
280 it('should warn about `forceUpdate` on unmounted components', () => {
281 const container = document.createElement('div');
282 document.body.appendChild(container);
packages/react/src/ReactNoopUpdateQueue.js
+7 -4
@@ -21,12 +21,15 @@ function warnNoop(publicInstance, callerName) {
21 }
22 warning(
23 false,
24 - '%s(...): Can only update a mounted or mounting component. ' +
25 - 'This usually means you called %s() on an unmounted component. ' +
26 - 'This is a no-op.\n\nPlease check the code for the %s component.',
27 - callerName,
24 + "Can't call %s on a component that is not yet mounted. " +
25 + 'This is a no-op, but it might indicate a bug in your application.\n\n' +
26 + 'To fix, assign the initial state in the %s constructor. ' +
27 + 'If the state needs to reflect an external data source, ' +
28 + 'you may also add a componentDidMount lifecycle hook to %s ' +
29 + 'and call setState there if the external data has changed.',
30 callerName,
31 componentName,
32 + componentName,
33 );
34 didWarnStateUpdateForUnmountedComponent[warningKey] = true;
35 }