@@ -187,13 +187,11 @@ type ResumableNode =
187187 number /* segment id */ ,
188188 ] ;
189189
190- type PostponedSegment = {
191- keyPath : KeyNode ,
192- segment : Segment ,
190+ type PostponedHoles = {
191+ workingMap : Map < KeyNode , ResumableParentNode > ,
192+ root : Array < ResumableNode > ,
193193} ;
194194
195- type PostponedHoles = Map < Root | SuspenseBoundary , Array < PostponedSegment >> ;
196-
197195type LegacyContext = {
198196 [ key : string ] : any ,
199197} ;
@@ -1681,6 +1679,10 @@ function trackPostpone(
16811679 task : Task ,
16821680 segment : Segment ,
16831681) : void {
1682+ segment . status = POSTPONED ;
1683+ // We know that this will leave a hole so we might as well assign an ID now.
1684+ segment . id = request . nextSegmentId ++ ;
1685+
16841686 const boundary = task . blockedBoundary ;
16851687 if ( boundary !== null && boundary . status === PENDING ) {
16861688 boundary . status = POSTPONED ;
@@ -1690,22 +1692,39 @@ function trackPostpone(
16901692 request . renderState ,
16911693 request . resumableState ,
16921694 ) ;
1695+
1696+ const boundaryKeyPath = boundary . keyPath ;
1697+ if ( boundaryKeyPath === null ) {
1698+ throw new Error (
1699+ 'It should not be possible to postpone at the root. This is a bug in React.' ,
1700+ ) ;
1701+ }
1702+ const children : Array < ResumableNode > = [];
1703+ const boundaryNode: ResumableParentNode = [
1704+ REPLAY_SUSPENSE_BOUNDARY,
1705+ boundaryKeyPath[1],
1706+ boundaryKeyPath[2],
1707+ children,
1708+ boundary.id,
1709+ ];
1710+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
1711+ addToResumableParent(boundaryNode, boundaryKeyPath, trackedPostpones);
16931712 }
1694- let postponedSegments = trackedPostpones . get ( task . blockedBoundary ) ;
1695- if ( postponedSegments === undefined ) {
1696- // This is the first time we've postponed this boundary.
1697- postponedSegments = [ ] ;
1698- trackedPostpones . set ( task . blockedBoundary , postponedSegments ) ;
1699- }
1700- if ( task . keyPath === null ) {
1713+
1714+ const keyPath = task . keyPath ;
1715+ if ( keyPath === null ) {
17011716 throw new Error (
17021717 'It should not be possible to postpone at the root. This is a bug in React.' ,
17031718 ) ;
17041719 }
1705- postponedSegments . push ( {
1706- keyPath : task . keyPath ,
1707- segment,
1708- } ) ;
1720+
1721+ const segmentNode : ResumableNode = [
1722+ RESUME_SEGMENT ,
1723+ keyPath [ 1 ] ,
1724+ keyPath [ 2 ] ,
1725+ segment . id ,
1726+ ] ;
1727+ addToResumableParent ( segmentNode , keyPath , trackedPostpones ) ;
17091728}
17101729
17111730function injectPostponedHole (
@@ -1727,9 +1746,6 @@ function injectPostponedHole(
17271746 // Assume we are text embedded at the trailing edge
17281747 true ,
17291748 ) ;
1730- newSegment . status = POSTPONED ;
1731- // We know that this will leave a hole so we might as well assign an ID now.
1732- segment . id = request . nextSegmentId ++ ;
17331749 segment . children . push ( newSegment ) ;
17341750 // Reset lastPushedText for current Segment since the new Segment "consumed" it
17351751 segment . lastPushedText = false ;
@@ -2200,9 +2216,6 @@ function retryTask(request: Request, task: Task): void {
22002216 // an error.
22012217 const trackedPostpones = request . trackedPostpones ;
22022218 task . abortSet . delete ( task ) ;
2203- segment . status = POSTPONED ;
2204- // We know that this will leave a hole so we might as well assign an ID now.
2205- segment . id = request . nextSegmentId ++ ;
22062219 const postponeInstance : Postpone = ( x : any ) ;
22072220 logPostpone ( request , postponeInstance . message ) ;
22082221 trackPostpone ( request , trackedPostpones , task , segment ) ;
@@ -2703,7 +2716,7 @@ function flushCompletedQueues(
27032716 if (
27042717 ! enablePostpone ||
27052718 request . trackedPostpones === null ||
2706- request . trackedPostpones . size === 0
2719+ request . trackedPostpones . root . length === 0
27072720 ) {
27082721 writePostamble ( destination , request . resumableState ) ;
27092722 }
@@ -2737,7 +2750,7 @@ export function startRender(request: Request): void {
27372750
27382751export function startPrerender ( request : Request ) : void {
27392752 // Start tracking postponed holes during this render.
2740- request . trackedPostpones = new Map ( ) ;
2753+ request . trackedPostpones = { workingMap : new Map ( ) , root : [ ] } ;
27412754 startRender ( request ) ;
27422755}
27432756
@@ -2810,13 +2823,13 @@ export function getResumableState(request: Request): ResumableState {
28102823function addToResumableParent (
28112824 node : ResumableNode ,
28122825 keyPath : KeyNode ,
2813- root : Array < ResumableNode > ,
2814- workingMap : Map < KeyNode , ResumableParentNode > ,
2826+ trackedPostpones : PostponedHoles ,
28152827) : void {
28162828 const parentKeyPath = keyPath [ 0 ] ;
28172829 if ( parentKeyPath === null ) {
2818- root . push ( node ) ;
2830+ trackedPostpones . root . push ( node ) ;
28192831 } else {
2832+ const workingMap = trackedPostpones . workingMap ;
28202833 let parentNode = workingMap . get ( parentKeyPath ) ;
28212834 if ( parentNode === undefined ) {
28222835 parentNode = ( [
@@ -2826,7 +2839,7 @@ function addToResumableParent(
28262839 ( [ ] : Array < ResumableNode > ) ,
28272840 ] : ResumableParentNode ) ;
28282841 workingMap . set ( parentKeyPath , parentNode ) ;
2829- addToResumableParent ( parentNode , parentKeyPath , root , workingMap ) ;
2842+ addToResumableParent ( parentNode , parentKeyPath , trackedPostpones ) ;
28302843 }
28312844 parentNode [ 3 ] . push ( node ) ;
28322845 }
@@ -2843,50 +2856,14 @@ export type PostponedState = {
28432856// Returns the state of a postponed request or null if nothing was postponed.
28442857export function getPostponedState ( request : Request ) : null | PostponedState {
28452858 const trackedPostpones = request . trackedPostpones ;
2846- if ( trackedPostpones === null || trackedPostpones . size === 0 ) {
2859+ if ( trackedPostpones === null || trackedPostpones . root . length === 0 ) {
28472860 return null ;
28482861 }
2849-
2850- // Next we build up a traversal tree of the resumable key paths and their
2851- // paths through suspense boundaries.
2852- const workingMap : Map < KeyNode , ResumableParentNode > = new Map ( ) ;
2853- const root : Array < ResumableNode > = [ ] ;
2854-
2855- trackedPostpones . forEach ( function (
2856- segments : Array < PostponedSegment > ,
2857- boundary : Root | SuspenseBoundary ,
2858- ) {
2859- if ( boundary !== null && boundary . keyPath !== null ) {
2860- const keyPath = boundary . keyPath ;
2861- const children : Array < ResumableNode > = [ ] ;
2862- const boundaryNode : ResumableParentNode = [
2863- REPLAY_SUSPENSE_BOUNDARY ,
2864- keyPath [ 1 ] ,
2865- keyPath [ 2 ] ,
2866- children ,
2867- boundary . id ,
2868- ] ;
2869- workingMap . set ( boundary . keyPath , boundaryNode ) ;
2870- addToResumableParent ( boundaryNode , keyPath , root , workingMap ) ;
2871- }
2872- for ( let i = 0 ; i < segments . length ; i ++ ) {
2873- const postponedSegment = segments [ i ] ;
2874- const keyPath = postponedSegment . keyPath ;
2875- const segmentNode : ResumableNode = [
2876- RESUME_SEGMENT ,
2877- keyPath [ 1 ] ,
2878- keyPath [ 2 ] ,
2879- postponedSegment . segment . id ,
2880- ] ;
2881- addToResumableParent ( segmentNode , keyPath , root , workingMap ) ;
2882- }
2883- } ) ;
2884-
28852862 return {
28862863 nextSegmentId : request . nextSegmentId ,
28872864 rootFormatContext : request . rootFormatContext ,
28882865 progressiveChunkSize : request . progressiveChunkSize ,
28892866 resumableState : request . resumableState ,
2890- resumablePath : root ,
2867+ resumablePath : trackedPostpones . root ,
28912868 } ;
28922869}
0 commit comments