moved non DEV methods to a new file called ReactFiberComponentTreeHook.js
This moves the non DEV methods to a new file called ReactFiberComponentTreeHook, updates existing references to DEV functions to remain inside DEV flags so they do not pull in ReactComponentTreeHook
Dominic Gannaway committed
Mar 6, 2017 at 14:19 UTC
b572e3c907e31700b140d750fd77977f0fd15885
12 files changed
+478
-486
src/isomorphic/classic/element/ReactDebugCurrentFrame.js
+8
-6
@@ -14,16 +14,18 @@
14
15
import type { Fiber } from 'ReactFiber';
16
import type { DebugID } from 'ReactInstanceType';
17
-import type { ComponentTreeHookDevType } from 'ReactComponentTreeHook';
17
18
const ReactDebugCurrentFrame = {};
19
20
if (__DEV__) {
22
- const {
21
+ var {
22
getStackAddendumByID,
24
- getStackAddendumByWorkInProgressFiber,
23
getCurrentStackAddendum,
26
- }: ComponentTreeHookDevType = (require('ReactComponentTreeHook'): any);
24
+ } = require('ReactComponentTreeHook');
25
+ var {
26
+ getStackAddendumByWorkInProgressFiber,
27
+ } = require('ReactFiberComponentTreeHook');
28
+
29
// Component that is being worked on
30
ReactDebugCurrentFrame.current = (null : Fiber | DebugID | null);
31
@@ -38,7 +40,7 @@ if (__DEV__) {
40
if (typeof current === 'number') {
41
// DebugID from Stack.
42
const debugID = current;
41
- stack = getStackAddendumByID && getStackAddendumByID(debugID);
43
+ stack = getStackAddendumByID(debugID);
44
} else if (typeof current.tag === 'number') {
45
// This is a Fiber.
46
// The stack will only be correct if this is a work in progress
@@ -47,7 +49,7 @@ if (__DEV__) {
49
stack = getStackAddendumByWorkInProgressFiber(workInProgress);
50
}
51
} else if (element !== null) {
50
- stack = getCurrentStackAddendum && getCurrentStackAddendum(element);
52
+ stack = getCurrentStackAddendum(element);
53
}
54
return stack;
55
};
src/isomorphic/classic/element/ReactElementValidator.js
+5
-3
@@ -19,7 +19,6 @@
19
'use strict';
20
21
var ReactCurrentOwner = require('ReactCurrentOwner');
22
-var ReactComponentTreeHook = require('ReactComponentTreeHook');
22
var ReactElement = require('ReactElement');
23
24
var checkReactTypeSpec = require('checkReactTypeSpec');
@@ -31,6 +30,9 @@ var getIteratorFn = require('getIteratorFn');
30
if (__DEV__) {
31
var warning = require('fbjs/lib/warning');
32
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
33
+ var {
34
+ getCurrentStackAddendum,
35
+ } = require('ReactComponentTreeHook');
36
}
37
38
function getDeclarationErrorAddendum() {
@@ -122,7 +124,7 @@ function validateExplicitKey(element, parentType) {
124
'%s%s See https://fb.me/react-warning-keys for more information.%s',
125
currentComponentErrorInfo,
126
childOwner,
125
- ReactComponentTreeHook.getCurrentStackAddendum(element)
127
+ getCurrentStackAddendum && getCurrentStackAddendum(element)
128
);
129
}
130
@@ -225,7 +227,7 @@ var ReactElementValidator = {
227
info += getDeclarationErrorAddendum();
228
}
229
228
- info += ReactComponentTreeHook.getCurrentStackAddendum();
230
+ info += getCurrentStackAddendum && getCurrentStackAddendum();
231
232
warning(
233
false,
src/isomorphic/hooks/ReactComponentTreeHook.js
+337
-420
@@ -12,476 +12,393 @@
12
13
'use strict';
14
15
+var ReactCurrentOwner = require('ReactCurrentOwner');
16
+var {
17
+ getStackAddendumByWorkInProgressFiber,
18
+ describeComponentFrame,
19
+} = require('ReactFiberComponentTreeHook');
20
+var invariant = require('fbjs/lib/invariant');
21
+var warning = require('fbjs/lib/warning');
22
+var getComponentName = require('getComponentName');
23
+
24
import type { ReactElement, Source } from 'ReactElementType';
25
import type { DebugID } from 'ReactInstanceType';
26
import type { Fiber } from 'ReactFiber';
27
19
-var getComponentName = require('getComponentName');
20
-var ReactTypeOfWork = require('ReactTypeOfWork');
21
-var {
22
- IndeterminateComponent,
23
- FunctionalComponent,
24
- ClassComponent,
25
- HostComponent,
26
-} = ReactTypeOfWork;
27
-
28
-function describeComponentFrame(name, source, ownerName) {
29
- return '\n in ' + (name || 'Unknown') + (
30
- source ?
31
- ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' +
32
- source.lineNumber + ')' :
33
- ownerName ?
34
- ' (created by ' + ownerName + ')' :
35
- ''
28
+function isNative(fn) {
29
+ // Based on isNative() from Lodash
30
+ var funcToString = Function.prototype.toString;
31
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
32
+ var reIsNative = RegExp('^' + funcToString
33
+ // Take an example native function source for comparison
34
+ .call(hasOwnProperty)
35
+ // Strip regex characters so we can use it for regex
36
+ .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
37
+ // Remove hasOwnProperty from the template to make it generic
38
+ .replace(
39
+ /hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
40
+ '$1.*?'
41
+ ) + '$'
42
);
37
-}
38
-
39
-function describeFiber(fiber : Fiber) : string {
40
- switch (fiber.tag) {
41
- case IndeterminateComponent:
42
- case FunctionalComponent:
43
- case ClassComponent:
44
- case HostComponent:
45
- var owner = fiber._debugOwner;
46
- var source = fiber._debugSource;
47
- var name = getComponentName(fiber);
48
- var ownerName = null;
49
- if (owner) {
50
- ownerName = getComponentName(owner);
51
- }
52
- return describeComponentFrame(name, source, ownerName);
53
- default:
54
- return '';
43
+ try {
44
+ var source = funcToString.call(fn);
45
+ return reIsNative.test(source);
46
+ } catch (err) {
47
+ return false;
48
}
49
}
50
58
-export type ComponentTreeHookType = {
59
- getStackAddendumByWorkInProgressFiber: (Fiber) => any,
60
-};
51
+var canUseCollections = (
52
+ // Array.from
53
+ typeof Array.from === 'function' &&
54
+ // Map
55
+ typeof Map === 'function' &&
56
+ isNative(Map) &&
57
+ // Map.prototype.keys
58
+ Map.prototype != null &&
59
+ typeof Map.prototype.keys === 'function' &&
60
+ isNative(Map.prototype.keys) &&
61
+ // Set
62
+ typeof Set === 'function' &&
63
+ isNative(Set) &&
64
+ // Set.prototype.keys
65
+ Set.prototype != null &&
66
+ typeof Set.prototype.keys === 'function' &&
67
+ isNative(Set.prototype.keys)
68
+);
69
+
70
+var setItem;
71
+var getItem;
72
+var removeItem;
73
+var getItemIDs;
74
+var addRoot;
75
+var removeRoot;
76
+var getRootIDs;
77
+
78
+if (canUseCollections) {
79
+ var itemMap = new Map();
80
+ var rootIDSet = new Set();
81
+
82
+ setItem = function(id, item) {
83
+ itemMap.set(id, item);
84
+ };
85
+ getItem = function(id) {
86
+ return itemMap.get(id);
87
+ };
88
+ removeItem = function(id) {
89
+ itemMap.delete(id);
90
+ };
91
+ getItemIDs = function() {
92
+ return Array.from(itemMap.keys());
93
+ };
94
62
-export type ComponentTreeHookDevType = {
63
- getStackAddendumByWorkInProgressFiber: (Fiber) => any,
64
- getStackAddendumByID: () => any,
65
- getCurrentStackAddendum: () => any,
66
- purgeUnmountedComponents: () => any,
67
- getOwnerID: (DebugID) => any,
68
- getParentID: (DebugID) => any,
69
- getDisplayName: (DebugID) => any,
70
- getText: (DebugID) => any,
71
- getUpdateCount: (DebugID) => any,
72
- getChildIDs: (DebugID) => any,
73
- getRegisteredIDs: () => any,
74
- getElement: () => any,
75
-};
95
+ addRoot = function(id) {
96
+ rootIDSet.add(id);
97
+ };
98
+ removeRoot = function(id) {
99
+ rootIDSet.delete(id);
100
+ };
101
+ getRootIDs = function() {
102
+ return Array.from(rootIDSet.keys());
103
+ };
104
77
-var ReactComponentTreeHook: ComponentTreeHookType = {
78
- // This function can only be called with a work-in-progress fiber and
79
- // only during begin or complete phase. Do not call it under any other
80
- // circumstances.
81
- getStackAddendumByWorkInProgressFiber(workInProgress : Fiber) : string {
82
- var info = '';
83
- var node = workInProgress;
84
- do {
85
- info += describeFiber(node);
86
- // Otherwise this return pointer might point to the wrong tree:
87
- node = node.return;
88
- } while (node);
89
- return info;
90
- },
91
-};
105
+} else {
106
+ var itemByKey = {};
107
+ var rootByKey = {};
108
93
-if (__DEV__) {
94
- var ReactCurrentOwner = require('ReactCurrentOwner');
95
- var invariant = require('fbjs/lib/invariant');
96
- var warning = require('fbjs/lib/warning');
97
-
98
- var isNative = function(fn) {
99
- // Based on isNative() from Lodash
100
- var funcToString = Function.prototype.toString;
101
- var hasOwnProperty = Object.prototype.hasOwnProperty;
102
- var reIsNative = RegExp('^' + funcToString
103
- // Take an example native function source for comparison
104
- .call(hasOwnProperty)
105
- // Strip regex characters so we can use it for regex
106
- .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
107
- // Remove hasOwnProperty from the template to make it generic
108
- .replace(
109
- /hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
110
- '$1.*?'
111
- ) + '$'
112
- );
113
- try {
114
- var source = funcToString.call(fn);
115
- return reIsNative.test(source);
116
- } catch (err) {
117
- return false;
118
- }
109
+ // Use non-numeric keys to prevent V8 performance issues:
110
+ // https://github.com/facebook/react/pull/7232
111
+ var getKeyFromID = function(id: DebugID): string {
112
+ return '.' + id;
113
+ };
114
+ var getIDFromKey = function(key: string): DebugID {
115
+ return parseInt(key.substr(1), 10);
116
};
117
121
- var canUseCollections = (
122
- // Array.from
123
- typeof Array.from === 'function' &&
124
- // Map
125
- typeof Map === 'function' &&
126
- isNative(Map) &&
127
- // Map.prototype.keys
128
- Map.prototype != null &&
129
- typeof Map.prototype.keys === 'function' &&
130
- isNative(Map.prototype.keys) &&
131
- // Set
132
- typeof Set === 'function' &&
133
- isNative(Set) &&
134
- // Set.prototype.keys
135
- Set.prototype != null &&
136
- typeof Set.prototype.keys === 'function' &&
137
- isNative(Set.prototype.keys)
138
- );
139
-
140
- var setItem;
141
- var getItem;
142
- var removeItem;
143
- var getItemIDs;
144
- var addRoot;
145
- var removeRoot;
146
- var getRootIDs;
118
+ setItem = function(id, item) {
119
+ var key = getKeyFromID(id);
120
+ itemByKey[key] = item;
121
+ };
122
+ getItem = function(id) {
123
+ var key = getKeyFromID(id);
124
+ return itemByKey[key];
125
+ };
126
+ removeItem = function(id) {
127
+ var key = getKeyFromID(id);
128
+ delete itemByKey[key];
129
+ };
130
+ getItemIDs = function() {
131
+ return Object.keys(itemByKey).map(getIDFromKey);
132
+ };
133
148
- if (canUseCollections) {
149
- var itemMap = new Map();
150
- var rootIDSet = new Set();
134
+ addRoot = function(id) {
135
+ var key = getKeyFromID(id);
136
+ rootByKey[key] = true;
137
+ };
138
+ removeRoot = function(id) {
139
+ var key = getKeyFromID(id);
140
+ delete rootByKey[key];
141
+ };
142
+ getRootIDs = function() {
143
+ return Object.keys(rootByKey).map(getIDFromKey);
144
+ };
145
+}
146
152
- setItem = function(id, item) {
153
- itemMap.set(id, item);
154
- };
155
- getItem = function(id) {
156
- return itemMap.get(id);
157
- };
158
- removeItem = function(id) {
159
- itemMap.delete(id);
160
- };
161
- getItemIDs = function() {
162
- return Array.from(itemMap.keys());
163
- };
147
+var unmountedIDs: Array<DebugID> = [];
148
165
- addRoot = function(id) {
166
- rootIDSet.add(id);
167
- };
168
- removeRoot = function(id) {
169
- rootIDSet.delete(id);
170
- };
171
- getRootIDs = function() {
172
- return Array.from(rootIDSet.keys());
173
- };
149
+function purgeDeep(id) {
150
+ var item = getItem(id);
151
+ if (item) {
152
+ var {childIDs} = item;
153
+ removeItem(id);
154
+ childIDs.forEach(purgeDeep);
155
+ }
156
+}
157
158
+function getDisplayName(element: ?ReactElement): string {
159
+ if (element == null) {
160
+ return '#empty';
161
+ } else if (typeof element === 'string' || typeof element === 'number') {
162
+ return '#text';
163
+ } else if (typeof element.type === 'string') {
164
+ return element.type;
165
} else {
176
- var itemByKey = {};
177
- var rootByKey = {};
166
+ return element.type.displayName || element.type.name || 'Unknown';
167
+ }
168
+}
169
179
- // Use non-numeric keys to prevent V8 performance issues:
180
- // https://github.com/facebook/react/pull/7232
181
- var getKeyFromID = function(id: DebugID): string {
182
- return '.' + id;
183
- };
184
- var getIDFromKey = function(key: string): DebugID {
185
- return parseInt(key.substr(1), 10);
186
- };
170
+function describeID(id: DebugID): string {
171
+ const name = ReactComponentTreeHook.getDisplayName(id);
172
+ const element = ReactComponentTreeHook.getElement(id);
173
+ const ownerID = ReactComponentTreeHook.getOwnerID(id);
174
+ let ownerName;
175
188
- setItem = function(id, item) {
189
- var key = getKeyFromID(id);
190
- itemByKey[key] = item;
191
- };
192
- getItem = function(id) {
193
- var key = getKeyFromID(id);
194
- return itemByKey[key];
195
- };
196
- removeItem = function(id) {
197
- var key = getKeyFromID(id);
198
- delete itemByKey[key];
199
- };
200
- getItemIDs = function() {
201
- return Object.keys(itemByKey).map(getIDFromKey);
202
- };
176
+ if (ownerID) {
177
+ ownerName = ReactComponentTreeHook.getDisplayName(ownerID);
178
+ }
179
+ warning(
180
+ element,
181
+ 'ReactComponentTreeHook: Missing React element for debugID %s when ' +
182
+ 'building stack',
183
+ id
184
+ );
185
+ if (element && name) {
186
+ return describeComponentFrame(name || '', element._source, ownerName || '');
187
+ }
188
+ return '';
189
+}
190
204
- addRoot = function(id) {
205
- var key = getKeyFromID(id);
206
- rootByKey[key] = true;
207
- };
208
- removeRoot = function(id) {
209
- var key = getKeyFromID(id);
210
- delete rootByKey[key];
211
- };
212
- getRootIDs = function() {
213
- return Object.keys(rootByKey).map(getIDFromKey);
191
+var ReactComponentTreeHook = {
192
+ onSetChildren(id: DebugID, nextChildIDs: Array<DebugID>): void {
193
+ var item = getItem(id);
194
+ invariant(item, 'Item must have been set');
195
+ item.childIDs = nextChildIDs;
196
+
197
+ for (var i = 0; i < nextChildIDs.length; i++) {
198
+ var nextChildID = nextChildIDs[i];
199
+ var nextChild = getItem(nextChildID);
200
+ invariant(
201
+ nextChild,
202
+ 'Expected hook events to fire for the child ' +
203
+ 'before its parent includes it in onSetChildren().'
204
+ );
205
+ invariant(
206
+ nextChild.childIDs != null ||
207
+ typeof nextChild.element !== 'object' ||
208
+ nextChild.element == null,
209
+ 'Expected onSetChildren() to fire for a container child ' +
210
+ 'before its parent includes it in onSetChildren().'
211
+ );
212
+ invariant(
213
+ nextChild.isMounted,
214
+ 'Expected onMountComponent() to fire for the child ' +
215
+ 'before its parent includes it in onSetChildren().'
216
+ );
217
+ if (nextChild.parentID == null) {
218
+ nextChild.parentID = id;
219
+ // TODO: This shouldn't be necessary but mounting a new root during in
220
+ // componentWillMount currently causes not-yet-mounted components to
221
+ // be purged from our tree data so their parent id is missing.
222
+ }
223
+ invariant(
224
+ nextChild.parentID === id,
225
+ 'Expected onBeforeMountComponent() parent and onSetChildren() to ' +
226
+ 'be consistent (%s has parents %s and %s).',
227
+ nextChildID,
228
+ nextChild.parentID,
229
+ id
230
+ );
231
+ }
232
+ },
233
+
234
+ onBeforeMountComponent(id: DebugID, element: ReactElement, parentID: DebugID): void {
235
+ var item = {
236
+ element,
237
+ parentID,
238
+ text: null,
239
+ childIDs: [],
240
+ isMounted: false,
241
+ updateCount: 0,
242
};
215
- }
243
+ setItem(id, item);
244
+ },
245
217
- const unmountedIDs: Array<DebugID> = [];
246
+ onBeforeUpdateComponent(id: DebugID, element: ReactElement): void {
247
+ var item = getItem(id);
248
+ if (!item || !item.isMounted) {
249
+ // We may end up here as a result of setState() in componentWillUnmount().
250
+ // In this case, ignore the element.
251
+ return;
252
+ }
253
+ item.element = element;
254
+ },
255
219
- const purgeDeep = function(id) {
256
+ onMountComponent(id: DebugID): void {
257
var item = getItem(id);
221
- if (item) {
222
- var {childIDs} = item;
223
- removeItem(id);
224
- childIDs.forEach(purgeDeep);
258
+ invariant(item, 'Item must have been set');
259
+ item.isMounted = true;
260
+ var isRoot = item.parentID === 0;
261
+ if (isRoot) {
262
+ addRoot(id);
263
}
226
- };
264
+ },
265
228
- const getDisplayNameFromElement = function(element: ?ReactElement): string {
229
- if (element == null) {
230
- return '#empty';
231
- } else if (typeof element === 'string' || typeof element === 'number') {
232
- return '#text';
233
- } else if (typeof element.type === 'string') {
234
- return element.type;
235
- } else {
236
- return element.type.displayName || element.type.name || 'Unknown';
266
+ onUpdateComponent(id: DebugID): void {
267
+ var item = getItem(id);
268
+ if (!item || !item.isMounted) {
269
+ // We may end up here as a result of setState() in componentWillUnmount().
270
+ // In this case, ignore the element.
271
+ return;
272
}
238
- };
273
+ item.updateCount++;
274
+ },
275
240
- const getDisplayName = function(id: DebugID): ?string {
241
- var element = getElement(id);
242
- if (!element) {
243
- return null;
276
+ onUnmountComponent(id: DebugID): void {
277
+ var item = getItem(id);
278
+ if (item) {
279
+ // We need to check if it exists.
280
+ // `item` might not exist if it is inside an error boundary, and a sibling
281
+ // error boundary child threw while mounting. Then this instance never
282
+ // got a chance to mount, but it still gets an unmounting event during
283
+ // the error boundary cleanup.
284
+ item.isMounted = false;
285
+ var isRoot = item.parentID === 0;
286
+ if (isRoot) {
287
+ removeRoot(id);
288
+ }
289
}
245
- return getDisplayNameFromElement(element);
246
- };
290
+ unmountedIDs.push(id);
291
+ },
292
248
- const getOwnerID = function(id: DebugID): ?DebugID {
249
- var element = getElement(id);
250
- if (!element || !element._owner) {
251
- return null;
293
+ purgeUnmountedComponents(): void {
294
+ if (ReactComponentTreeHook._preventPurging) {
295
+ // Should only be used for testing.
296
+ return;
297
}
253
- return element._owner._debugID;
254
- };
255
-
256
- const describeID = function(id: DebugID): string {
257
- var name = getDisplayName(id);
258
- var element = getElement(id);
259
- var ownerID = getOwnerID(id);
260
- var ownerName;
261
- if (ownerID) {
262
- ownerName = getDisplayName(ownerID);
298
+
299
+ for (var i = 0; i < unmountedIDs.length; i++) {
300
+ var id = unmountedIDs[i];
301
+ purgeDeep(id);
302
}
264
- warning(
265
- element,
266
- 'ReactComponentTreeHook: Missing React element for debugID %s when ' +
267
- 'building stack',
268
- id
269
- );
270
- return describeComponentFrame(name, element && element._source, ownerName);
271
- };
303
+ unmountedIDs.length = 0;
304
+ },
305
273
- const getElement = function(id: DebugID): ?ReactElement {
306
+ isMounted(id: DebugID): boolean {
307
var item = getItem(id);
275
- return item ? item.element : null;
276
- };
308
+ return item ? item.isMounted : false;
309
+ },
310
278
- const getParentID = function(id: DebugID): ?DebugID {
279
- var item = getItem(id);
280
- return item ? item.parentID : null;
281
- };
311
+ getCurrentStackAddendum(topElement: ?ReactElement): string {
312
+ var info = '';
313
+ if (topElement) {
314
+ var name = getDisplayName(topElement);
315
+ var owner = topElement._owner;
316
+ info += describeComponentFrame(
317
+ name,
318
+ topElement._source,
319
+ owner && getComponentName(owner)
320
+ );
321
+ }
322
+
323
+ var currentOwner = ReactCurrentOwner.current;
324
+ if (currentOwner) {
325
+ if (typeof currentOwner.tag === 'number') {
326
+ const workInProgress = ((currentOwner : any) : Fiber);
327
+ // Safe because if current owner exists, we are reconciling,
328
+ // and it is guaranteed to be the work-in-progress version.
329
+ info += getStackAddendumByWorkInProgressFiber(workInProgress);
330
+ } else if (typeof currentOwner._debugID === 'number') {
331
+ info += ReactComponentTreeHook.getStackAddendumByID(currentOwner._debugID);
332
+ }
333
+ }
334
+ return info;
335
+ },
336
283
- const getStackAddendumByID = function(id: ?DebugID): string {
337
+ getStackAddendumByID(id: ?DebugID): string {
338
var info = '';
339
while (id) {
340
info += describeID(id);
287
- id = getParentID(id);
341
+ id = ReactComponentTreeHook.getParentID(id);
342
}
343
return info;
290
- };
291
-
292
- ReactComponentTreeHook = Object.assign({}, ReactComponentTreeHook, {
293
- onSetChildren(id: DebugID, nextChildIDs: Array<DebugID>): void {
294
- var item = getItem(id);
295
- invariant(item, 'Item must have been set');
296
- item.childIDs = nextChildIDs;
297
-
298
- for (var i = 0; i < nextChildIDs.length; i++) {
299
- var nextChildID = nextChildIDs[i];
300
- var nextChild = getItem(nextChildID);
301
- invariant(
302
- nextChild,
303
- 'Expected hook events to fire for the child ' +
304
- 'before its parent includes it in onSetChildren().'
305
- );
306
- invariant(
307
- nextChild.childIDs != null ||
308
- typeof nextChild.element !== 'object' ||
309
- nextChild.element == null,
310
- 'Expected onSetChildren() to fire for a container child ' +
311
- 'before its parent includes it in onSetChildren().'
312
- );
313
- invariant(
314
- nextChild.isMounted,
315
- 'Expected onMountComponent() to fire for the child ' +
316
- 'before its parent includes it in onSetChildren().'
317
- );
318
- if (nextChild.parentID == null) {
319
- nextChild.parentID = id;
320
- // TODO: This shouldn't be necessary but mounting a new root during in
321
- // componentWillMount currently causes not-yet-mounted components to
322
- // be purged from our tree data so their parent id is missing.
323
- }
324
- invariant(
325
- nextChild.parentID === id,
326
- 'Expected onBeforeMountComponent() parent and onSetChildren() to ' +
327
- 'be consistent (%s has parents %s and %s).',
328
- nextChildID,
329
- nextChild.parentID,
330
- id
331
- );
332
- }
333
- },
334
-
335
- onBeforeMountComponent(id: DebugID, element: ReactElement, parentID: DebugID): void {
336
- var item = {
337
- element,
338
- parentID,
339
- text: null,
340
- childIDs: [],
341
- isMounted: false,
342
- updateCount: 0,
343
- };
344
- setItem(id, item);
345
- },
346
-
347
- onBeforeUpdateComponent(id: DebugID, element: ReactElement): void {
348
- var item = getItem(id);
349
- if (!item || !item.isMounted) {
350
- // We may end up here as a result of setState() in componentWillUnmount().
351
- // In this case, ignore the element.
352
- return;
353
- }
354
- item.element = element;
355
- },
344
+ },
345
357
- onMountComponent(id: DebugID): void {
358
- var item = getItem(id);
359
- invariant(item, 'Item must have been set');
360
- item.isMounted = true;
361
- var isRoot = item.parentID === 0;
362
- if (isRoot) {
363
- addRoot(id);
364
- }
365
- },
366
-
367
- onUpdateComponent(id: DebugID): void {
368
- var item = getItem(id);
369
- if (!item || !item.isMounted) {
370
- // We may end up here as a result of setState() in componentWillUnmount().
371
- // In this case, ignore the element.
372
- return;
373
- }
374
- item.updateCount++;
375
- },
376
-
377
- onUnmountComponent(id: DebugID): void {
378
- var item = getItem(id);
379
- if (item) {
380
- // We need to check if it exists.
381
- // `item` might not exist if it is inside an error boundary, and a sibling
382
- // error boundary child threw while mounting. Then this instance never
383
- // got a chance to mount, but it still gets an unmounting event during
384
- // the error boundary cleanup.
385
- item.isMounted = false;
386
- var isRoot = item.parentID === 0;
387
- if (isRoot) {
388
- removeRoot(id);
389
- }
390
- }
391
- unmountedIDs.push(id);
392
- },
346
+ getChildIDs(id: DebugID): Array<DebugID> {
347
+ var item = getItem(id);
348
+ return item ? item.childIDs : [];
349
+ },
350
394
- purgeUnmountedComponents(): void {
395
- if (ReactComponentTreeHook._preventPurging) {
396
- // Should only be used for testing.
397
- return;
398
- }
351
+ getDisplayName(id: DebugID): ?string {
352
+ var element = ReactComponentTreeHook.getElement(id);
353
+ if (!element) {
354
+ return null;
355
+ }
356
+ return getDisplayName(element);
357
+ },
358
400
- for (var i = 0; i < unmountedIDs.length; i++) {
401
- var id = unmountedIDs[i];
402
- purgeDeep(id);
403
- }
404
- unmountedIDs.length = 0;
405
- },
406
-
407
- isMounted(id: DebugID): boolean {
408
- var item = getItem(id);
409
- return item ? item.isMounted : false;
410
- },
411
-
412
- getCurrentStackAddendum(topElement: ?ReactElement): string {
413
- var info = '';
414
- if (topElement) {
415
- var name = getDisplayNameFromElement(topElement);
416
- var owner = topElement._owner;
417
- info += describeComponentFrame(
418
- name,
419
- topElement._source,
420
- owner && getComponentName(owner)
421
- );
422
- }
359
+ getElement(id: DebugID): ?ReactElement {
360
+ var item = getItem(id);
361
+ return item ? item.element : null;
362
+ },
363
424
- var currentOwner = ReactCurrentOwner.current;
425
- if (currentOwner) {
426
- if (typeof currentOwner.tag === 'number') {
427
- const workInProgress = ((currentOwner : any) : Fiber);
428
- // Safe because if current owner exists, we are reconciling,
429
- // and it is guaranteed to be the work-in-progress version.
430
- info += ReactComponentTreeHook.getStackAddendumByWorkInProgressFiber(workInProgress);
431
- } else if (typeof currentOwner._debugID === 'number') {
432
- info += getStackAddendumByID(currentOwner._debugID);
433
- }
434
- }
435
- return info;
436
- },
364
+ getOwnerID(id: DebugID): ?DebugID {
365
+ var element = ReactComponentTreeHook.getElement(id);
366
+ if (!element || !element._owner) {
367
+ return null;
368
+ }
369
+ return element._owner._debugID;
370
+ },
371
438
- getStackAddendumByID,
372
+ getParentID(id: DebugID): ?DebugID {
373
+ var item = getItem(id);
374
+ return item ? item.parentID : null;
375
+ },
376
440
- getChildIDs(id: DebugID): Array<DebugID> {
441
- var item = getItem(id);
442
- return item ? item.childIDs : [];
443
- },
377
+ getSource(id: DebugID): ?Source {
378
+ var item = getItem(id);
379
+ var element = item ? item.element : null;
380
+ var source = element != null ? element._source : null;
381
+ return source;
382
+ },
383
445
- getDisplayName(id: DebugID): ?string {
446
- var element = getElement(id);
447
- if (!element) {
448
- return null;
449
- }
450
- return getDisplayNameFromElement(element);
451
- },
452
-
453
- getElement,
454
-
455
- getOwnerID,
456
-
457
- getParentID,
458
-
459
- getSource(id: DebugID): ?Source {
460
- var item = getItem(id);
461
- var element = item ? item.element : null;
462
- var source = element != null ? element._source : null;
463
- return source;
464
- },
465
-
466
- getText(id: DebugID): ?string {
467
- var element = getElement(id);
468
- if (typeof element === 'string') {
469
- return element;
470
- } else if (typeof element === 'number') {
471
- return '' + element;
472
- } else {
473
- return null;
474
- }
475
- },
384
+ getText(id: DebugID): ?string {
385
+ var element = ReactComponentTreeHook.getElement(id);
386
+ if (typeof element === 'string') {
387
+ return element;
388
+ } else if (typeof element === 'number') {
389
+ return '' + element;
390
+ } else {
391
+ return null;
392
+ }
393
+ },
394
477
- getUpdateCount(id: DebugID): number {
478
- var item = getItem(id);
479
- return item ? item.updateCount : 0;
480
- },
395
+ getUpdateCount(id: DebugID): number {
396
+ var item = getItem(id);
397
+ return item ? item.updateCount : 0;
398
+ },
399
482
- getRootIDs,
483
- getRegisteredIDs: getItemIDs,
484
- });
485
-}
400
+ getRootIDs,
401
+ getRegisteredIDs: getItemIDs,
402
+};
403
404
module.exports = ReactComponentTreeHook;
src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js
+7
-2
@@ -12,7 +12,6 @@
12
'use strict';
13
14
var DOMProperty = require('DOMProperty');
15
-var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
15
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
16
17
var warning = require('fbjs/lib/warning');
@@ -20,10 +19,16 @@ var warning = require('fbjs/lib/warning');
19
var warnedProperties = {};
20
var rARIA = new RegExp('^(aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');
21
22
+if (__DEV__) {
23
+ var {
24
+ getStackAddendumByID,
25
+ } = require('react/lib/ReactComponentTreeHook');
26
+}
27
+
28
function getStackAddendum(debugID) {
29
if (debugID != null) {
30
// This can only happen on Stack
26
- return ReactComponentTreeHook.getStackAddendumByID(debugID);
31
+ return getStackAddendumByID && getStackAddendumByID(debugID);
32
} else {
33
// This can only happen on Fiber
34
return ReactDebugCurrentFiber.getCurrentFiberStackAddendum();
src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js
+7
-3
@@ -11,17 +11,21 @@
11
12
'use strict';
13
14
-var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
14
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
16
-
15
var warning = require('fbjs/lib/warning');
16
17
+if (__DEV__) {
18
+ var {
19
+ getStackAddendumByID,
20
+ } = require('react/lib/ReactComponentTreeHook');
21
+}
22
+
23
var didWarnValueNull = false;
24
25
function getStackAddendum(debugID) {
26
if (debugID != null) {
27
// This can only happen on Stack
24
- return ReactComponentTreeHook.getStackAddendumByID(debugID);
28
+ return getStackAddendumByID && getStackAddendumByID(debugID);
29
} else {
30
// This can only happen on Fiber
31
return ReactDebugCurrentFiber.getCurrentFiberStackAddendum();
src/renderers/shared/ReactDebugTool.js
+20
-37
@@ -14,6 +14,7 @@
14
15
var ReactInvalidSetStateWarningHook = require('ReactInvalidSetStateWarningHook');
16
var ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook');
17
+var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
18
var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
19
20
var performanceNow = require('fbjs/lib/performanceNow');
@@ -22,7 +23,6 @@ var warning = require('fbjs/lib/warning');
23
import type { ReactElement } from 'ReactElementType';
24
import type { DebugID } from 'ReactInstanceType';
25
import type { Operation } from 'ReactHostOperationHistoryHook';
25
-import type { ComponentTreeHookDevType } from 'ReactComponentTreeHook';
26
27
type Hook = any;
28
@@ -67,20 +67,8 @@ export type FlushHistory = Array<HistoryItem>;
67
var ReactDebugTool = ((null: any): typeof ReactDebugTool);
68
69
if (__DEV__) {
70
- const hooks = [];
71
- const didHookThrowForEvent = {};
72
- const ReactComponentTreeHook: ComponentTreeHookDevType = (require('react/lib/ReactComponentTreeHook'): any);
73
- const {
74
- purgeUnmountedComponents,
75
- getOwnerID,
76
- getParentID,
77
- getDisplayName,
78
- getText,
79
- getUpdateCount,
80
- getChildIDs,
81
- getRegisteredIDs,
82
- getElement,
83
- } = ReactComponentTreeHook;
70
+ var hooks = [];
71
+ var didHookThrowForEvent = {};
72
73
const callHook = function(event, fn, context, arg1, arg2, arg3, arg4, arg5) {
74
try {
@@ -120,24 +108,22 @@ if (__DEV__) {
108
var lifeCycleTimerHasWarned = false;
109
110
const clearHistory = function() {
123
- if (purgeUnmountedComponents) {
124
- purgeUnmountedComponents();
125
- }
111
+ ReactComponentTreeHook.purgeUnmountedComponents();
112
ReactHostOperationHistoryHook.clearHistory();
113
};
114
115
const getTreeSnapshot = function(registeredIDs) {
116
return registeredIDs.reduce((tree, id) => {
131
- var ownerID = getOwnerID(id);
132
- var parentID = getParentID(id);
117
+ var ownerID = ReactComponentTreeHook.getOwnerID(id);
118
+ var parentID = ReactComponentTreeHook.getParentID(id);
119
tree[id] = {
134
- displayName: getDisplayName(id),
135
- text: getText(id),
136
- updateCount: getUpdateCount(id),
137
- childIDs: getChildIDs(id),
120
+ displayName: ReactComponentTreeHook.getDisplayName(id),
121
+ text: ReactComponentTreeHook.getText(id),
122
+ updateCount: ReactComponentTreeHook.getUpdateCount(id),
123
+ childIDs: ReactComponentTreeHook.getChildIDs(id),
124
// Text nodes don't have owners but this is close enough.
125
ownerID: ownerID ||
140
- parentID && getOwnerID(parentID) ||
126
+ parentID && ReactComponentTreeHook.getOwnerID(parentID) ||
127
0,
128
parentID,
129
};
@@ -158,16 +144,13 @@ if (__DEV__) {
144
}
145
146
if (previousMeasurements.length || previousOperations.length) {
161
- if (getRegisteredIDs) {
162
- var registeredIDs = getRegisteredIDs();
163
-
164
- flushHistory.push({
165
- duration: performanceNow() - previousStartTime,
166
- measurements: previousMeasurements || [],
167
- operations: previousOperations || [],
168
- treeSnapshot: getTreeSnapshot(registeredIDs),
169
- });
170
- }
147
+ var registeredIDs = ReactComponentTreeHook.getRegisteredIDs();
148
+ flushHistory.push({
149
+ duration: performanceNow() - previousStartTime,
150
+ measurements: previousMeasurements || [],
151
+ operations: previousOperations || [],
152
+ treeSnapshot: getTreeSnapshot(registeredIDs),
153
+ });
154
}
155
156
clearHistory();
@@ -270,7 +253,7 @@ if (__DEV__) {
253
if (!isProfiling || !canUsePerformanceMeasure) {
254
return false;
255
}
273
- var element = getElement && getElement(debugID);
256
+ var element = ReactComponentTreeHook.getElement(debugID);
257
if (element == null || typeof element !== 'object') {
258
return false;
259
}
@@ -297,7 +280,7 @@ if (__DEV__) {
280
}
281
282
var markName = `${debugID}::${markType}`;
300
- var displayName = getDisplayName && getDisplayName(debugID) || 'Unknown';
283
+ var displayName = ReactComponentTreeHook.getDisplayName(debugID) || 'Unknown';
284
285
// Chrome has an issue of dropping markers recorded too fast:
286
// https://bugs.chromium.org/p/chromium/issues/detail?id=640652
src/renderers/shared/fiber/ReactDebugCurrentFiber.js
+1
-1
@@ -18,7 +18,7 @@ type LifeCyclePhase = 'render' | 'getChildContext';
18
19
if (__DEV__) {
20
var getComponentName = require('getComponentName');
21
- var { getStackAddendumByWorkInProgressFiber } = require('react/lib/ReactComponentTreeHook');
21
+ var { getStackAddendumByWorkInProgressFiber } = require('ReactFiberComponentTreeHook');
22
}
23
24
function getCurrentFiberOwnerName() : string | null {
src/renderers/shared/fiber/ReactFiberScheduler.js
+1
-1
@@ -37,7 +37,7 @@ var {
37
const { reset } = require('ReactFiberStack');
38
var {
39
getStackAddendumByWorkInProgressFiber,
40
-} = require('react/lib/ReactComponentTreeHook');
40
+} = require('ReactFiberComponentTreeHook');
41
var { logCapturedError } = require('ReactFiberErrorLogger');
42
var { invokeGuardedCallback } = require('ReactErrorUtils');
43
src/renderers/shared/stack/reconciler/ReactRef.js
+3
-6
@@ -16,15 +16,12 @@ var ReactOwner = require('ReactOwner');
16
17
import type { ReactInstance } from 'ReactInstanceType';
18
import type { ReactElement } from 'ReactElementType';
19
-import type { ComponentTreeHookDevType } from 'ReactComponentTreeHook';
19
20
var ReactRef = {};
21
22
if (__DEV__) {
23
var ReactCompositeComponentTypes = require('ReactCompositeComponentTypes');
25
- var {
26
- getStackAddendumByID,
27
- }: ComponentTreeHookDevType = (require('react/lib/ReactComponentTreeHook'): any);
24
+ var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
25
var warning = require('fbjs/lib/warning');
26
27
var warnedAboutStatelessRefs = {};
@@ -49,14 +46,14 @@ function attachRef(ref, component, owner) {
46
if (element && element._source) {
47
warningKey = element._source.fileName + ':' + element._source.lineNumber;
48
}
52
- if (!warnedAboutStatelessRefs[warningKey] && getStackAddendumByID) {
49
+ if (!warnedAboutStatelessRefs[warningKey]) {
50
warnedAboutStatelessRefs[warningKey] = true;
51
warning(
52
false,
53
'Stateless function components cannot be given refs. ' +
54
'Attempts to access this ref will fail.%s%s',
55
info,
59
- getStackAddendumByID(component._debugID)
56
+ ReactComponentTreeHook.getStackAddendumByID(component._debugID)
57
);
58
}
59
}
src/shared/ReactFiberComponentTreeHook.js
new
+77
@@ -0,0 +1,77 @@
1
+/**
2
+ * Copyright 2016-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
+ * @flow
10
+ * @providesModule ReactFiberComponentTreeHook
11
+ */
12
+
13
+'use strict';
14
+
15
+var ReactTypeOfWork = require('ReactTypeOfWork');
16
+var {
17
+ IndeterminateComponent,
18
+ FunctionalComponent,
19
+ ClassComponent,
20
+ HostComponent,
21
+} = ReactTypeOfWork;
22
+var getComponentName = require('getComponentName');
23
+
24
+import type { Fiber } from 'ReactFiber';
25
+import type { Source } from 'ReactElementType';
26
+
27
+function describeComponentFrame(name, source: Source, ownerName) {
28
+ return '\n in ' + (name || 'Unknown') + (
29
+ source ?
30
+ ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' +
31
+ source.lineNumber + ')' :
32
+ ownerName ?
33
+ ' (created by ' + ownerName + ')' :
34
+ ''
35
+ );
36
+}
37
+
38
+function describeFiber(fiber : Fiber) : string {
39
+ switch (fiber.tag) {
40
+ case IndeterminateComponent:
41
+ case FunctionalComponent:
42
+ case ClassComponent:
43
+ case HostComponent:
44
+ var owner = fiber._debugOwner;
45
+ var source = fiber._debugSource;
46
+ var name = getComponentName(fiber);
47
+ var ownerName = null;
48
+ if (owner) {
49
+ ownerName = getComponentName(owner);
50
+ }
51
+ if (source) {
52
+ return describeComponentFrame(name, source, ownerName);
53
+ }
54
+ return '';
55
+ default:
56
+ return '';
57
+ }
58
+}
59
+
60
+// This function can only be called with a work-in-progress fiber and
61
+// only during begin or complete phase. Do not call it under any other
62
+// circumstances.
63
+function getStackAddendumByWorkInProgressFiber(workInProgress : Fiber) : string {
64
+ var info = '';
65
+ var node = workInProgress;
66
+ do {
67
+ info += describeFiber(node);
68
+ // Otherwise this return pointer might point to the wrong tree:
69
+ node = node.return;
70
+ } while (node);
71
+ return info;
72
+}
73
+
74
+module.exports = {
75
+ getStackAddendumByWorkInProgressFiber,
76
+ describeComponentFrame,
77
+};
src/shared/utils/flattenChildren.js
+2
-6
@@ -12,8 +12,6 @@
12
13
'use strict';
14
15
-import type { ComponentTreeHookDevType } from 'ReactComponentTreeHook';
16
-
15
var KeyEscapeUtils = require('KeyEscapeUtils');
16
var traverseAllChildren = require('traverseAllChildren');
17
var warning = require('fbjs/lib/warning');
@@ -53,16 +51,14 @@ function flattenSingleChildIntoContext(
51
if (!ReactComponentTreeHook) {
52
ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
53
}
56
- const { getStackAddendumByID }: ComponentTreeHookDevType = (ReactComponentTreeHook: any);
57
-
58
- if (!keyUnique && getStackAddendumByID) {
54
+ if (!keyUnique) {
55
warning(
56
false,
57
'flattenChildren(...): Encountered two children with the same key, ' +
58
'`%s`. Child keys must be unique; when two children share a key, only ' +
59
'the first child will be used.%s',
60
KeyEscapeUtils.unescape(name),
65
- getStackAddendumByID(selfDebugID)
61
+ ReactComponentTreeHook.getStackAddendumByID(selfDebugID)
62
);
63
}
64
}
src/umd/ReactUMDEntry.js
+10
-1
@@ -17,8 +17,17 @@ var React = require('React');
17
var ReactUMDEntry = Object.assign({
18
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
19
ReactCurrentOwner: require('react/lib/ReactCurrentOwner'),
20
- ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'),
20
},
21
}, React);
22
23
+if (__DEV__) {
24
+ Object.assign(
25
+ ReactUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
26
+ {
27
+ // ReactComponentTreeHook should not be included in production.
28
+ ReactComponentTreeHook: require('react/lib/ReactComponentTreeHook'),
29
+ }
30
+ );
31
+}
32
+
33
module.exports = ReactUMDEntry;