Skip to content

Commit 5f25f7b

Browse files
committed
Warn about readContext() during class render-phase setState()
1 parent e342fa0 commit 5f25f7b

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

packages/react-reconciler/src/ReactUpdateQueue.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ import type {Fiber} from './ReactFiber';
8888
import type {ExpirationTime} from './ReactFiberExpirationTime';
8989

9090
import {NoWork} from './ReactFiberExpirationTime';
91+
import {
92+
stashContextDependenciesInDEV,
93+
unstashContextDependenciesInDEV,
94+
} from './ReactFiberNewContext';
9195
import {Callback, ShouldCapture, DidCapture} from 'shared/ReactSideEffectTags';
9296
import {ClassComponent} from 'shared/ReactWorkTags';
9397

@@ -348,6 +352,7 @@ function getStateFromUpdate<State>(
348352
if (typeof payload === 'function') {
349353
// Updater function
350354
if (__DEV__) {
355+
stashContextDependenciesInDEV();
351356
if (
352357
debugRenderPhaseSideEffects ||
353358
(debugRenderPhaseSideEffectsForStrictMode &&
@@ -356,7 +361,11 @@ function getStateFromUpdate<State>(
356361
payload.call(instance, prevState, nextProps);
357362
}
358363
}
359-
return payload.call(instance, prevState, nextProps);
364+
const nextState = payload.call(instance, prevState, nextProps);
365+
if (__DEV__) {
366+
unstashContextDependenciesInDEV();
367+
}
368+
return nextState;
360369
}
361370
// State object
362371
return payload;
@@ -372,6 +381,7 @@ function getStateFromUpdate<State>(
372381
if (typeof payload === 'function') {
373382
// Updater function
374383
if (__DEV__) {
384+
stashContextDependenciesInDEV();
375385
if (
376386
debugRenderPhaseSideEffects ||
377387
(debugRenderPhaseSideEffectsForStrictMode &&
@@ -381,6 +391,9 @@ function getStateFromUpdate<State>(
381391
}
382392
}
383393
partialState = payload.call(instance, prevState, nextProps);
394+
if (__DEV__) {
395+
unstashContextDependenciesInDEV();
396+
}
384397
} else {
385398
// Partial state object
386399
partialState = payload;

packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,31 @@ describe('ReactNewContext', () => {
13461346
expect(ReactNoop.flush()).toEqual(['App', 'App#renderConsumer']);
13471347
expect(ReactNoop.getChildren()).toEqual([span('goodbye')]);
13481348
});
1349+
1350+
it('warns when reading context inside render phase class setState updater', () => {
1351+
const ThemeContext = React.createContext('light');
1352+
1353+
class Cls extends React.Component {
1354+
state = {};
1355+
render() {
1356+
this.setState(() => {
1357+
readContext(ThemeContext);
1358+
});
1359+
return null;
1360+
}
1361+
}
1362+
1363+
ReactNoop.render(<Cls />);
1364+
expect(ReactNoop.flush).toWarnDev(
1365+
[
1366+
'Context can only be read while React is rendering',
1367+
'Cannot update during an existing state transition',
1368+
],
1369+
{
1370+
withoutStack: 1,
1371+
},
1372+
);
1373+
});
13491374
});
13501375

13511376
describe('useContext', () => {

0 commit comments

Comments
 (0)