mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #221 from gaearon/heuristic
Use a heuristic for locating roots
This commit is contained in:
+81
-20
@@ -539,11 +539,6 @@ export function attach(
|
||||
// When a mount or update is in progress, this value tracks the root that is being operated on.
|
||||
let currentRootID: number = -1;
|
||||
|
||||
// Track the order in which roots were added.
|
||||
// We will use it to disambiguate roots when restoring selection between reloads.
|
||||
let nextRootIndex = 0;
|
||||
const rootInsertionOrder: Map<number, number> = new Map();
|
||||
|
||||
function getFiberID(primaryFiber: Fiber): number {
|
||||
if (!fiberToIDMap.has(primaryFiber)) {
|
||||
const id = getUID();
|
||||
@@ -1148,7 +1143,7 @@ export function attach(
|
||||
// If we have not been profiling, then we can just walk the tree and build up its current state as-is.
|
||||
hook.getFiberRoots(rendererID).forEach(root => {
|
||||
currentRootID = getFiberID(getPrimaryFiber(root.current));
|
||||
rootInsertionOrder.set(currentRootID, nextRootIndex++);
|
||||
setRootPseudoKey(currentRootID, root.current);
|
||||
|
||||
if (isProfiling) {
|
||||
// If profiling is active, store commit time and duration, and the current interactions.
|
||||
@@ -1217,19 +1212,19 @@ export function attach(
|
||||
current.memoizedState != null && current.memoizedState.element != null;
|
||||
if (!wasMounted && isMounted) {
|
||||
// Mount a new root.
|
||||
rootInsertionOrder.set(currentRootID, nextRootIndex++);
|
||||
setRootPseudoKey(currentRootID, current);
|
||||
mountFiberRecursively(current, null);
|
||||
} else if (wasMounted && isMounted) {
|
||||
// Update an existing root.
|
||||
updateFiberRecursively(current, alternate, null);
|
||||
} else if (wasMounted && !isMounted) {
|
||||
// Unmount an existing root.
|
||||
rootInsertionOrder.delete(currentRootID);
|
||||
removeRootPseudoKey(currentRootID);
|
||||
recordUnmount(current, false);
|
||||
}
|
||||
} else {
|
||||
// Mount a new root.
|
||||
rootInsertionOrder.set(currentRootID, nextRootIndex++);
|
||||
setRootPseudoKey(currentRootID, current);
|
||||
mountFiberRecursively(current, null);
|
||||
}
|
||||
|
||||
@@ -2097,18 +2092,84 @@ export function attach(
|
||||
mightBeOnTrackedPath = mightSiblingsBeOnTrackedPath;
|
||||
}
|
||||
|
||||
function getPathFrame(fiber: Fiber): PathFrame {
|
||||
const { displayName, key } = getDataForFiber(fiber);
|
||||
let index = fiber.index;
|
||||
if (fiber.tag === HostRoot) {
|
||||
// Roots don't have a real index.
|
||||
// Instead, we'll use the order in which it mounted.
|
||||
const id = getFiberID(getPrimaryFiber(fiber));
|
||||
const order = rootInsertionOrder.get(id);
|
||||
if (typeof order !== 'number') {
|
||||
throw new Error('Expected mounted root to have known insertion order.');
|
||||
// Roots don't have a real persistent identity.
|
||||
// A root's "pseudo key" is "childDisplayName:indexWithThatName".
|
||||
// For example, "App:0" or, in case of similar roots, "Story:0", "Story:1", etc.
|
||||
// We will use this to try to disambiguate roots when restoring selection between reloads.
|
||||
const rootPseudoKeys: Map<number, string> = new Map();
|
||||
const rootDisplayNameCounter: Map<string, number> = new Map();
|
||||
|
||||
function setRootPseudoKey(id: number, fiber: Fiber) {
|
||||
let preferredDisplayName = null;
|
||||
let fallbackDisplayName = null;
|
||||
let child = fiber.child;
|
||||
// Go at most three levels deep into direct children
|
||||
// while searching for a child that has a displayName.
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (child === null) {
|
||||
break;
|
||||
}
|
||||
index = order;
|
||||
const displayName = getDataForFiber(child).displayName;
|
||||
if (displayName !== null) {
|
||||
// Prefer display names that we get from user-defined components.
|
||||
// We want to avoid using e.g. 'Suspense' unless we find nothing else.
|
||||
if (typeof child.type === 'function') {
|
||||
// There's a few user-defined tags, but we'll prefer the ones
|
||||
// that are usually explicitly named (function or class components).
|
||||
preferredDisplayName = displayName;
|
||||
} else if (fallbackDisplayName === null) {
|
||||
fallbackDisplayName = displayName;
|
||||
}
|
||||
}
|
||||
if (preferredDisplayName !== null) {
|
||||
break;
|
||||
}
|
||||
child = child.child;
|
||||
}
|
||||
const name = preferredDisplayName || fallbackDisplayName || 'Unknown';
|
||||
const counter = rootDisplayNameCounter.get(name) || 0;
|
||||
rootDisplayNameCounter.set(name, counter + 1);
|
||||
const pseudoKey = `${name}:${counter}`;
|
||||
rootPseudoKeys.set(id, pseudoKey);
|
||||
}
|
||||
|
||||
function removeRootPseudoKey(id: number) {
|
||||
const pseudoKey = rootPseudoKeys.get(id);
|
||||
if (pseudoKey === undefined) {
|
||||
throw new Error('Expected root pseudo key to be known.');
|
||||
}
|
||||
const name = pseudoKey.substring(0, pseudoKey.lastIndexOf(':'));
|
||||
const counter = rootDisplayNameCounter.get(name);
|
||||
if (counter === undefined) {
|
||||
throw new Error('Expected counter to be known.');
|
||||
}
|
||||
if (counter > 1) {
|
||||
rootDisplayNameCounter.set(name, counter - 1);
|
||||
} else {
|
||||
rootDisplayNameCounter.delete(name);
|
||||
}
|
||||
rootPseudoKeys.delete(id);
|
||||
}
|
||||
|
||||
function getPathFrame(fiber: Fiber): PathFrame {
|
||||
let { displayName, key } = getDataForFiber(fiber);
|
||||
const index = fiber.index;
|
||||
switch (fiber.tag) {
|
||||
case HostRoot:
|
||||
// Roots don't have a real displayName, index, or key.
|
||||
// Instead, we'll use the pseudo key (childDisplayName:indexWithThatName).
|
||||
const id = getFiberID(getPrimaryFiber(fiber));
|
||||
const pseudoKey = rootPseudoKeys.get(id);
|
||||
if (pseudoKey === undefined) {
|
||||
throw new Error('Expected mounted root to have known pseudo key.');
|
||||
}
|
||||
displayName = pseudoKey;
|
||||
break;
|
||||
case HostComponent:
|
||||
displayName = fiber.type;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {
|
||||
displayName,
|
||||
|
||||
Reference in New Issue
Block a user