@samitouri / QOS-React / commits / 309dea5b4c

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;