@@ -2266,16 +2266,11 @@ export function attach(
22662266 debug ( 'recordUnmount()' , fiber , null ) ;
22672267 }
22682268
2269- if ( trackedPathMatchFiber !== null ) {
2269+ if ( trackedPathMatchInstance = = = fiberInstance ) {
22702270 // We're in the process of trying to restore previous selection.
22712271 // If this fiber matched but is being unmounted, there's no use trying.
22722272 // Reset the state so we don't keep holding onto it.
2273- if (
2274- fiber === trackedPathMatchFiber ||
2275- fiber === trackedPathMatchFiber . alternate
2276- ) {
2277- setTrackedPath ( null ) ;
2278- }
2273+ setTrackedPath ( null ) ;
22792274 }
22802275
22812276 const id = fiberInstance . id ;
@@ -2386,6 +2381,14 @@ export function attach(
23862381 traceNearestHostComponentUpdate : boolean ,
23872382 virtualLevel : number , // the nth level of virtual instances
23882383 ) : void {
2384+ // If we have the tree selection from previous reload, try to match this Instance.
2385+ // Also remember whether to do the same for siblings.
2386+ const mightSiblingsBeOnTrackedPath =
2387+ updateVirtualTrackedPathStateBeforeMount (
2388+ virtualInstance ,
2389+ reconcilingParent ,
2390+ ) ;
2391+
23892392 const stashedParent = reconcilingParent ;
23902393 const stashedPrevious = previouslyReconciledSibling ;
23912394 const stashedRemaining = remainingReconcilingChildren ;
@@ -2406,13 +2409,16 @@ export function attach(
24062409 reconcilingParent = stashedParent ;
24072410 previouslyReconciledSibling = stashedPrevious ;
24082411 remainingReconcilingChildren = stashedRemaining ;
2412+ updateTrackedPathStateAfterMount ( mightSiblingsBeOnTrackedPath ) ;
24092413 }
24102414 }
24112415
24122416 function recordVirtualUnmount ( instance : VirtualInstance ) {
2413- if ( trackedPathMatchFiber !== null ) {
2417+ if ( trackedPathMatchInstance === instance ) {
24142418 // We're in the process of trying to restore previous selection.
2415- // TODO: Handle virtual instances on the tracked path.
2419+ // If this fiber matched but is being unmounted, there's no use trying.
2420+ // Reset the state so we don't keep holding onto it.
2421+ setTrackedPath ( null ) ;
24162422 }
24172423
24182424 const id = instance . id ;
@@ -2521,17 +2527,20 @@ export function attach(
25212527 debug ( 'mountFiberRecursively()' , fiber , reconcilingParent ) ;
25222528 }
25232529
2524- // If we have the tree selection from previous reload, try to match this Fiber.
2525- // Also remember whether to do the same for siblings.
2526- const mightSiblingsBeOnTrackedPath =
2527- updateTrackedPathStateBeforeMount ( fiber ) ;
2528-
25292530 const shouldIncludeInTree = ! shouldFilterFiber ( fiber ) ;
25302531 let newInstance = null ;
25312532 if ( shouldIncludeInTree ) {
25322533 newInstance = recordMount ( fiber , reconcilingParent ) ;
25332534 insertChild ( newInstance ) ;
25342535 }
2536+
2537+ // If we have the tree selection from previous reload, try to match this Fiber.
2538+ // Also remember whether to do the same for siblings.
2539+ const mightSiblingsBeOnTrackedPath = updateTrackedPathStateBeforeMount (
2540+ fiber ,
2541+ newInstance ,
2542+ ) ;
2543+
25352544 const stashedParent = reconcilingParent ;
25362545 const stashedPrevious = previouslyReconciledSibling ;
25372546 const stashedRemaining = remainingReconcilingChildren ;
@@ -2570,14 +2579,15 @@ export function attach(
25702579 const fallbackChildFragment = primaryChildFragment
25712580 ? primaryChildFragment . sibling
25722581 : null ;
2573- const fallbackChild = fallbackChildFragment
2574- ? fallbackChildFragment . child
2575- : null ;
2576- if ( fallbackChild !== null ) {
2577- mountChildrenRecursively (
2578- fallbackChild ,
2579- traceNearestHostComponentUpdate ,
2580- ) ;
2582+ if ( fallbackChildFragment ) {
2583+ const fallbackChild = fallbackChildFragment . child ;
2584+ if ( fallbackChild !== null ) {
2585+ updateTrackedPathStateBeforeMount ( fallbackChildFragment , null ) ;
2586+ mountChildrenRecursively (
2587+ fallbackChild ,
2588+ traceNearestHostComponentUpdate ,
2589+ ) ;
2590+ }
25812591 }
25822592 } else {
25832593 let primaryChild : Fiber | null = null ;
@@ -2587,6 +2597,7 @@ export function attach(
25872597 primaryChild = fiber . child ;
25882598 } else if ( fiber . child !== null ) {
25892599 primaryChild = fiber . child . child ;
2600+ updateTrackedPathStateBeforeMount ( fiber . child , null ) ;
25902601 }
25912602 if ( primaryChild !== null ) {
25922603 mountChildrenRecursively (
@@ -5262,13 +5273,15 @@ export function attach(
52625273 // Remember if we're trying to restore the selection after reload.
52635274 // In that case, we'll do some extra checks for matching mounts.
52645275 let trackedPath : Array < PathFrame > | null = null;
5265- let trackedPathMatchFiber: Fiber | null = null;
5276+ let trackedPathMatchFiber: Fiber | null = null; // This is the deepest unfiltered match of a Fiber.
5277+ let trackedPathMatchInstance: DevToolsInstance | null = null; // This is the deepest matched filtered Instance.
52665278 let trackedPathMatchDepth = -1;
52675279 let mightBeOnTrackedPath = false;
52685280
52695281 function setTrackedPath(path: Array< PathFrame > | null) {
52705282 if ( path === null ) {
52715283 trackedPathMatchFiber = null ;
5284+ trackedPathMatchInstance = null ;
52725285 trackedPathMatchDepth = - 1 ;
52735286 mightBeOnTrackedPath = false ;
52745287 }
@@ -5278,7 +5291,10 @@ export function attach(
52785291 // We call this before traversing a new mount.
52795292 // It remembers whether this Fiber is the next best match for tracked path.
52805293 // The return value signals whether we should keep matching siblings or not.
5281- function updateTrackedPathStateBeforeMount ( fiber : Fiber ) : boolean {
5294+ function updateTrackedPathStateBeforeMount (
5295+ fiber : Fiber ,
5296+ fiberInstance : null | FiberInstance ,
5297+ ) : boolean {
52825298 if ( trackedPath === null || ! mightBeOnTrackedPath ) {
52835299 // Fast path: there's nothing to track so do nothing and ignore siblings.
52845300 return false ;
@@ -5306,6 +5322,9 @@ export function attach(
53065322 ) {
53075323 // We have our next match.
53085324 trackedPathMatchFiber = fiber ;
5325+ if ( fiberInstance !== null ) {
5326+ trackedPathMatchInstance = fiberInstance ;
5327+ }
53095328 trackedPathMatchDepth ++ ;
53105329 // Are we out of frames to match?
53115330 // $FlowFixMe[incompatible-use] found when upgrading Flow
@@ -5322,13 +5341,69 @@ export function attach(
53225341 return false ;
53235342 }
53245343 }
5344+ if ( trackedPathMatchFiber === null && fiberInstance === null ) {
5345+ // We're now looking for a Virtual Instance. It might be inside filtered Fibers
5346+ // so we keep looking below.
5347+ return true ;
5348+ }
53255349 // This Fiber's parent is on the path, but this Fiber itself isn't.
53265350 // There's no need to check its children--they won't be on the path either.
53275351 mightBeOnTrackedPath = false;
53285352 // However, one of its siblings may be on the path so keep searching.
53295353 return true;
53305354 }
53315355
5356+ function updateVirtualTrackedPathStateBeforeMount (
5357+ virtualInstance : VirtualInstance ,
5358+ parentInstance : null | DevToolsInstance ,
5359+ ) : boolean {
5360+ if ( trackedPath === null || ! mightBeOnTrackedPath ) {
5361+ // Fast path: there's nothing to track so do nothing and ignore siblings.
5362+ return false ;
5363+ }
5364+ // Check if we've matched our nearest unfiltered parent so far.
5365+ if (trackedPathMatchInstance === parentInstance) {
5366+ const actualFrame = getVirtualPathFrame ( virtualInstance ) ;
5367+ // $FlowFixMe[incompatible-use] found when upgrading Flow
5368+ const expectedFrame = trackedPath [ trackedPathMatchDepth + 1 ] ;
5369+ if ( expectedFrame === undefined ) {
5370+ throw new Error ( 'Expected to see a frame at the next depth.' ) ;
5371+ }
5372+ if (
5373+ actualFrame . index === expectedFrame . index &&
5374+ actualFrame . key === expectedFrame . key &&
5375+ actualFrame . displayName === expectedFrame . displayName
5376+ ) {
5377+ // We have our next match.
5378+ trackedPathMatchFiber = null ; // Don't bother looking in Fibers anymore. We're deeper now.
5379+ trackedPathMatchInstance = virtualInstance ;
5380+ trackedPathMatchDepth ++ ;
5381+ // Are we out of frames to match?
5382+ // $FlowFixMe[incompatible-use] found when upgrading Flow
5383+ if ( trackedPathMatchDepth === trackedPath . length - 1 ) {
5384+ // There's nothing that can possibly match afterwards.
5385+ // Don't check the children.
5386+ mightBeOnTrackedPath = false ;
5387+ } else {
5388+ // Check the children, as they might reveal the next match.
5389+ mightBeOnTrackedPath = true ;
5390+ }
5391+ // In either case, since we have a match, we don't need
5392+ // to check the siblings. They'll never match.
5393+ return false ;
5394+ }
5395+ }
5396+ if (trackedPathMatchFiber !== null) {
5397+ // We're still looking for a Fiber which might be underneath this instance.
5398+ return true ;
5399+ }
5400+ // This Instance's parent is on the path, but this Instance itself isn't.
5401+ // There's no need to check its children--they won't be on the path either.
5402+ mightBeOnTrackedPath = false;
5403+ // However, one of its siblings may be on the path so keep searching.
5404+ return true;
5405+ }
5406+
53325407 function updateTrackedPathStateAfterMount (
53335408 mightSiblingsBeOnTrackedPath : boolean ,
53345409 ) {
@@ -5428,6 +5503,14 @@ export function attach(
54285503 } ;
54295504 }
54305505
5506+ function getVirtualPathFrame ( virtualInstance : VirtualInstance ) : PathFrame {
5507+ return {
5508+ displayName : virtualInstance . data . name || '' ,
5509+ key : virtualInstance . data . key == null ? null : virtualInstance . data . key ,
5510+ index : - 1 , // We use -1 to indicate that this is a virtual path frame.
5511+ } ;
5512+ }
5513+
54315514 // Produces a serializable representation that does a best effort
54325515 // of identifying a particular Fiber between page reloads.
54335516 // The return path will contain Fibers that are "invisible" to the store
@@ -5437,13 +5520,20 @@ export function attach(
54375520 if ( devtoolsInstance === undefined ) {
54385521 return null ;
54395522 }
5440- if ( devtoolsInstance . kind !== FIBER_INSTANCE ) {
5441- // TODO: Handle VirtualInstance.
5442- return null ;
5443- }
54445523
5445- let fiber : null | Fiber = devtoolsInstance . data ;
54465524 const keyPath = [ ] ;
5525+
5526+ let inst : DevToolsInstance = devtoolsInstance ;
5527+ while ( inst . kind === VIRTUAL_INSTANCE ) {
5528+ keyPath . push ( getVirtualPathFrame ( inst ) ) ;
5529+ if ( inst . parent === null ) {
5530+ // This is a bug but non-essential. We should've found a root instance.
5531+ return null ;
5532+ }
5533+ inst = inst . parent ;
5534+ }
5535+
5536+ let fiber: null | Fiber = inst.data;
54475537 while (fiber !== null) {
54485538 // $FlowFixMe[incompatible-call] found when upgrading Flow
54495539 keyPath . push ( getPathFrame ( fiber ) ) ;
@@ -5459,20 +5549,12 @@ export function attach(
54595549 // Nothing to match.
54605550 return null ;
54615551 }
5462- if (trackedPathMatchFiber === null) {
5552+ if (trackedPathMatchInstance === null) {
54635553 // We didn't find anything.
54645554 return null ;
54655555 }
5466- // Find the closest Fiber store is aware of.
5467- let fiber: null | Fiber = trackedPathMatchFiber;
5468- while (fiber !== null && shouldFilterFiber ( fiber ) ) {
5469- fiber = fiber . return ;
5470- }
5471- if (fiber === null) {
5472- return null ;
5473- }
54745556 return {
5475- id : getFiberIDThrows ( fiber ) ,
5557+ id : trackedPathMatchInstance . id ,
54765558 // $FlowFixMe[incompatible-use] found when upgrading Flow
54775559 isFullMatch : trackedPathMatchDepth === trackedPath . length - 1 ,
54785560 } ;
0 commit comments