Implement getPathForElement to serialize the selected path
Note this doesn't restore the selection yet.
Dan Abramov committed
Apr 23, 2019 at 16:01 UTC
3bb837b683fcd41f48ca522b09ad7918e7fca6f7
2 files changed
+56
-18
src/backend/renderer.js
+53
-16
@@ -324,7 +324,7 @@ export function attach(
324
// TODO: we might want to change the data structure once we no longer suppport Stack versions of `getData`.
325
// TODO: Keep in sync with getElementType()
326
function getDataForFiber(fiber: Fiber): FiberData {
327
- const { elementType, type, key, tag } = fiber;
327
+ const { elementType, type, key, index, tag } = fiber;
328
329
// This is to support lazy components with a Promise as the type.
330
// see https://github.com/facebook/react/pull/13397
@@ -345,6 +345,7 @@ export function attach(
345
fiberData = {
346
displayName: getDisplayName(resolvedType),
347
key,
348
+ index,
349
type: ElementTypeClass,
350
};
351
break;
@@ -353,6 +354,7 @@ export function attach(
354
fiberData = {
355
displayName: getDisplayName(resolvedType),
356
key,
357
+ index,
358
type: ElementTypeFunction,
359
};
360
break;
@@ -360,6 +362,7 @@ export function attach(
362
fiberData = {
363
displayName: null,
364
key,
365
+ index,
366
type: ElementTypeEventComponent,
367
};
368
break;
@@ -376,6 +379,7 @@ export function attach(
379
fiberData = {
380
displayName,
381
key,
382
+ index,
383
type: ElementTypeEventTarget,
384
};
385
break;
@@ -388,6 +392,7 @@ export function attach(
392
fiberData = {
393
displayName,
394
key,
395
+ index,
396
type: ElementTypeForwardRef,
397
};
398
break;
@@ -395,6 +400,7 @@ export function attach(
400
return {
401
displayName: null,
402
key: null,
403
+ index: 0,
404
type: ElementTypeRoot,
405
};
406
case HostPortal:
@@ -404,6 +410,7 @@ export function attach(
410
return {
411
displayName: null,
412
key,
413
+ index,
414
type: ElementTypeOtherOrUnknown,
415
};
416
case MemoComponent:
@@ -417,6 +424,7 @@ export function attach(
424
fiberData = {
425
displayName,
426
key,
427
+ index,
428
type: ElementTypeMemo,
429
};
430
break;
@@ -430,6 +438,7 @@ export function attach(
438
return {
439
displayName: null,
440
key: null,
441
+ index,
442
type: ElementTypeOtherOrUnknown,
443
};
444
case CONTEXT_PROVIDER_NUMBER:
@@ -444,6 +453,7 @@ export function attach(
453
fiberData = {
454
displayName,
455
key,
456
+ index,
457
type: ElementTypeContext,
458
};
459
break;
@@ -462,6 +472,7 @@ export function attach(
472
fiberData = {
473
displayName,
474
key,
475
+ index,
476
type: ElementTypeContext,
477
};
478
break;
@@ -470,6 +481,7 @@ export function attach(
481
fiberData = {
482
displayName: null,
483
key,
484
+ index,
485
type: ElementTypeOtherOrUnknown,
486
};
487
break;
@@ -479,6 +491,7 @@ export function attach(
491
fiberData = {
492
displayName: 'Suspense',
493
key,
494
+ index,
495
type: ElementTypeSuspense,
496
};
497
break;
@@ -487,6 +500,7 @@ export function attach(
500
fiberData = {
501
displayName: `Profiler(${fiber.memoizedProps.id})`,
502
key,
503
+ index,
504
type: ElementTypeProfiler,
505
};
506
break;
@@ -496,6 +510,7 @@ export function attach(
510
fiberData = {
511
displayName: null,
512
key,
513
+ index,
514
type: ElementTypeOtherOrUnknown,
515
};
516
break;
@@ -2000,26 +2015,48 @@ export function attach(
2015
trackedPath = path;
2016
}
2017
2003
- function getPathForElement(id: number): Array<PathFrame> {
2004
- // TODO: this is not a real path.
2005
- return [
2006
- {
2007
- index: id,
2008
- key: null,
2009
- displayName: null,
2010
- },
2011
- ];
2018
+ function getPathFrame(fiber: Fiber): PathFrame {
2019
+ let { displayName, key, index } = getDataForFiber(fiber);
2020
+ if (fiber.tag === HostRoot) {
2021
+ // Roots don't have a real index.
2022
+ // Instead, we'll use the order in which it mounted.
2023
+ const id = getFiberID(getPrimaryFiber(fiber));
2024
+ const order = rootInsertionOrder.get(id);
2025
+ if (typeof order !== 'number') {
2026
+ throw new Error('Expected mounted root to have known insertion order.');
2027
+ }
2028
+ index = order;
2029
+ }
2030
+ return {
2031
+ displayName,
2032
+ key,
2033
+ index,
2034
+ };
2035
+ }
2036
+
2037
+ // Produces a serializable representation that does a best effort
2038
+ // of identifying a particular Fiber between page reloads.
2039
+ // The return path will contain Fibers that are "invisible" to the store
2040
+ // because their keys and indexes are important to restoring the selection.
2041
+ function getPathForElement(id: number): Array<PathFrame> | null {
2042
+ let fiber = idToFiberMap.get(id);
2043
+ if (fiber == null) {
2044
+ return null;
2045
+ }
2046
+ const keyPath = [];
2047
+ while (fiber !== null) {
2048
+ keyPath.push(getPathFrame(fiber));
2049
+ fiber = fiber.return;
2050
+ }
2051
+ keyPath.reverse();
2052
+ return keyPath;
2053
}
2054
2055
function getBestMatchForTrackedPath(): PathMatch | null {
2015
- // TODO: this is not a real lookup.
2056
if (trackedPath !== null) {
2017
- const id = trackedPath[0].index;
2018
- const fiber = idToFiberMap.get(id);
2019
- if (fiber !== null) {
2020
- return { id, isFullMatch: true };
2021
- }
2057
+ console.log('Looking for match for path: ', trackedPath);
2058
}
2059
+ // TODO: implement this.
2060
return null;
2061
}
2062
src/backend/types.js
+3
-2
@@ -14,7 +14,8 @@ export type Fiber = Object;
14
// (e.g. props, state, context, hooks) then we could add a bitmask field for this
15
// to keep the number of attributes small.
16
export type FiberData = {|
17
- key: React$Key | null,
17
+ key: string | null,
18
+ index: number,
19
displayName: string | null,
20
type: ElementType,
21
|};
@@ -115,7 +116,7 @@ export type RendererInterface = {
116
getInteractions: (rootID: number) => Interactions,
117
getProfilingDataForDownload: (rootID: number) => Object,
118
getProfilingSummary: (rootID: number) => ProfilingSummary,
118
- getPathForElement: (id: number) => Array<PathFrame>,
119
+ getPathForElement: (id: number) => Array<PathFrame> | null,
120
handleCommitFiberRoot: (fiber: Object) => void,
121
handleCommitFiberUnmount: (fiber: Object) => void,
122
inspectElement: (id: number) => InspectedElement | null,