@samitouri / QOS-React / commits / 3bb837b683

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,