Track which lifecycle method we're in during DEV
Use this to detect setState inside of render instead of relying on the owner.
Andrew Clark committed
Feb 22, 2017 at 13:38 UTC
309dea5b4c77f267734f3ddbf852929f2c64c061
4 files changed
+47
-8
src/renderers/shared/fiber/ReactFiberBeginWork.js
+15
-1
@@ -66,6 +66,7 @@ var invariant = require('invariant');
66
67
if (__DEV__) {
68
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
69
+ var ReactDebugLifeCycle = require('ReactDebugLifeCycle');
70
var warning = require('warning');
71
var warnedAboutStatelessRefs = {};
72
}
@@ -230,7 +231,11 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
231
232
if (__DEV__) {
233
ReactCurrentOwner.current = workInProgress;
234
+ ReactDebugLifeCycle.current = workInProgress;
235
+ ReactDebugLifeCycle.phase = 'render';
236
nextChildren = fn(nextProps, context);
237
+ ReactDebugLifeCycle.current = null;
238
+ ReactDebugLifeCycle.phase = null;
239
} else {
240
nextChildren = fn(nextProps, context);
241
}
@@ -279,7 +284,16 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
284
285
// Rerender
286
ReactCurrentOwner.current = workInProgress;
282
- const nextChildren = instance.render();
287
+ let nextChildren;
288
+ if (__DEV__) {
289
+ ReactDebugLifeCycle.current = workInProgress;
290
+ ReactDebugLifeCycle.phase = 'render';
291
+ nextChildren = instance.render();
292
+ ReactDebugLifeCycle.current = null;
293
+ ReactDebugLifeCycle.phase = null;
294
+ } else {
295
+ nextChildren = instance.render();
296
+ }
297
reconcileChildren(current, workInProgress, nextChildren);
298
// Memoize props and state using the values we just used to render.
299
// TODO: Restructure so we never read values from the instance.
src/renderers/shared/fiber/ReactFiberReconciler.js
+4
-6
@@ -33,7 +33,7 @@ if (__DEV__) {
33
var warning = require('warning');
34
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
35
var warning = require('warning');
36
- var ReactCurrentOwner = require('ReactCurrentOwner');
36
+ var ReactDebugLifeCycle = require('ReactDebugLifeCycle');
37
var { getComponentName } = require('ReactFiberTreeReflection');
38
}
39
@@ -148,16 +148,14 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
148
149
function scheduleTopLevelUpdate(current : Fiber, element : ReactNodeList, callback : ?Function) {
150
if (__DEV__) {
151
- const owner = ReactCurrentOwner.current;
152
- if (owner && typeof owner.tag === 'number') {
153
- const ownerFiber : Fiber = (owner : any);
151
+ if (ReactDebugLifeCycle.current !== null) {
152
warning(
155
- false,
153
+ ReactDebugLifeCycle.phase !== 'render',
154
'Render methods should be a pure function of props and state; ' +
155
'triggering nested component updates from render is not allowed. ' +
156
'If necessary, trigger nested updates in componentDidUpdate.\n\n' +
157
'Check the render method of %s.',
160
- getComponentName(ownerFiber)
158
+ getComponentName(ReactDebugLifeCycle.current)
159
);
160
}
161
}
src/renderers/shared/fiber/ReactFiberScheduler.js
+4
-1
@@ -90,6 +90,7 @@ if (__DEV__) {
90
var warning = require('warning');
91
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
92
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
93
+ var ReactDebugLifeCycle = require('ReactDebugLifeCycle');
94
var {
95
isProcessingChildContext,
96
onEndProcessingChildContext,
@@ -113,7 +114,7 @@ if (__DEV__) {
114
false,
115
'setState(...): Cannot call setState() inside getChildContext()',
116
);
116
- } else if (ReactCurrentOwner.current != null) {
117
+ } else if (ReactDebugLifeCycle.phase === 'render') {
118
warning(
119
false,
120
'Cannot update during an existing state transition (such as within ' +
@@ -880,6 +881,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
881
ReactCurrentOwner.current = null;
882
if (__DEV__) {
883
ReactDebugCurrentFiber.current = null;
884
+ ReactDebugLifeCycle.current = null;
885
+ ReactDebugLifeCycle.phase = null;
886
onEndProcessingChildContext();
887
}
888
// It is no longer valid because this unit of work failed.
src/renderers/shared/fiber/isomorphic/ReactDebugLifeCycle.js
new
+24
@@ -0,0 +1,24 @@
1
+/**
2
+ * Copyright 2013-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactDebugLifeCycle
10
+ * @flow
11
+ */
12
+
13
+'use strict';
14
+
15
+import type { Fiber } from 'ReactFiber';
16
+
17
+type LifeCyclePhase = 'render';
18
+
19
+const ReactDebugLifeCycle = {
20
+ current: (null : Fiber | null),
21
+ phase: (null : LifeCyclePhase | null),
22
+};
23
+
24
+module.exports = ReactDebugLifeCycle;