22
33import React , { type Node , type Element } from 'react'
44import type { Visitor , YieldFrame , Frame , AbstractElement } from './types'
5- import { visitChildren , resumeVisitChildren } from './visitor'
5+ import { visitChildren , resumeVisitChildren , update } from './visitor'
66import { getChildrenArray } from './element'
77
8- import {
9- updateFunctionComponent ,
10- updateClassComponent ,
11- updateLazyComponent
12- } from './render'
13-
148import {
159 setCurrentContextStore ,
1610 setCurrentContextMap ,
@@ -21,7 +15,29 @@ const {
2115 ReactCurrentDispatcher
2216} = ( React : any ) . __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
2317
24- let prevDispatcher = ReactCurrentDispatcher . current
18+ /** wrapWithDispatcher accepts a function and wraps it
19+ in one that sets up our ReactCurrentDispatcher and
20+ resets it afterwards */
21+ function wrapWithDispatcher < T : Function > (exec: T): T {
22+ // $FlowFixMe
23+ return ( ...args ) = > {
24+ const prevDispatcher = ReactCurrentDispatcher . current
25+
26+ try {
27+ // The "Dispatcher" is what handles hook calls and
28+ // a React internal that needs to be set to our dispatcher
29+ ReactCurrentDispatcher . current = Dispatcher
30+ return exec ( ...args )
31+ } finally {
32+ // We're resetting the dispatcher after we're done
33+ ReactCurrentDispatcher . current = prevDispatcher
34+ }
35+ }
36+ }
37+
38+ const resumeWithDispatcher = wrapWithDispatcher ( resumeVisitChildren )
39+ const visitWithDispatcher = wrapWithDispatcher ( visitChildren )
40+ const updateWithDispatcher = wrapWithDispatcher ( update )
2541
2642/** visitChildren walks all elements (depth-first) and while it walks the
2743 element tree some components will suspend and put a `Frame` onto
@@ -34,50 +50,35 @@ const updateWithFrame = (
3450 visitor : Visitor
3551) : Promise < void > => {
3652 if ( frame . kind === 'frame.yield' ) {
37- const yieldFrame : YieldFrame = frame
38-
39- return new Promise ( resolve => {
53+ return new Promise ( ( resolve , reject ) => {
4054 setImmediate ( ( ) => {
41- prevDispatcher = ReactCurrentDispatcher . current
42- ReactCurrentDispatcher . current = Dispatcher
43- resumeVisitChildren ( yieldFrame , queue , visitor )
44- ReactCurrentDispatcher . current = prevDispatcher
45- resolve ( )
55+ try {
56+ resumeWithDispatcher ( frame , queue , visitor )
57+ resolve ( )
58+ } catch ( err ) {
59+ reject ( err )
60+ }
4661 } )
4762 } )
4863 }
4964
5065 return frame . thenable . then ( ( ) => {
51- prevDispatcher = ReactCurrentDispatcher . current
52- ReactCurrentDispatcher . current = Dispatcher
53-
54- let children = [ ]
55-
5666 // Update the component after we've suspended to rerender it,
5767 // at which point we'll actually get its children
58- if ( frame . kind === 'frame.class' ) {
59- children = updateClassComponent ( queue , frame )
60- } else if ( frame . kind === 'frame.hooks' ) {
61- children = updateFunctionComponent ( queue , frame )
62- } else if ( frame . kind === 'frame.lazy' ) {
63- children = updateLazyComponent ( queue , frame )
64- }
65-
68+ const children = updateWithDispatcher ( frame , queue )
6669 // Now continue walking the previously suspended component's
6770 // children (which might also suspend)
68- visitChildren ( getChildrenArray ( children ) , queue , visitor )
69- ReactCurrentDispatcher . current = prevDispatcher
71+ visitWithDispatcher ( getChildrenArray ( children ) , queue , visitor )
7072 } )
7173}
7274
7375const flushFrames = ( queue : Frame [ ] , visitor : Visitor ) : Promise < void > => {
74- if ( queue . length === 0 ) {
75- return Promise . resolve ( )
76- }
77-
78- return updateWithFrame ( queue . shift ( ) , queue, visitor) . then ( ( ) =>
79- flushFrames ( queue , visitor )
80- )
76+ const frame = queue . shift ( )
77+ return frame
78+ ? updateWithFrame ( frame , queue , visitor ) . then ( ( ) =>
79+ flushFrames ( queue , visitor )
80+ )
81+ : Promise . resolve ( )
8182}
8283
8384const defaultVisitor = ( ) => undefined
@@ -93,17 +94,9 @@ const renderPrepass = (element: Node, visitor?: Visitor): Promise<void> => {
9394 setCurrentContextStore ( new Map ( ) )
9495
9596 try {
96- // The "Dispatcher" is what handles hook calls and
97- // a React internal that needs to be set to our
98- // dispatcher and reset after we're done
99- prevDispatcher = ReactCurrentDispatcher . current
100- ReactCurrentDispatcher . current = Dispatcher
101-
102- visitChildren ( getChildrenArray ( element ) , queue , fn )
97+ visitWithDispatcher ( getChildrenArray ( element ) , queue , fn )
10398 } catch ( error ) {
10499 return Promise . reject ( error )
105- } finally {
106- ReactCurrentDispatcher . current = prevDispatcher
107100 }
108101
109102 return flushFrames ( queue , fn )
0 commit comments