@@ -15,6 +15,7 @@ import {
1515 Mode ,
1616} from "./TypeOfWork" ;
1717import { prepareToUseHooks , finishHooks , bailoutHooks } from "./FiberHooks" ;
18+ import { NoWork } from "./FiberExpirationTime" ;
1819
1920let didReceiveUpdate = false ;
2021
@@ -26,15 +27,23 @@ export function beginWork(current, workInProgress, renderExpirationTime) {
2627 didReceiveUpdate = true ;
2728 } else if ( updateExpirationTime < renderExpirationTime ) {
2829 didReceiveUpdate = false ;
30+ return bailoutOnAlreadyFinishedWork (
31+ current ,
32+ workInProgress ,
33+ renderExpirationTime ,
34+ ) ;
2935 }
3036 } else {
3137 didReceiveUpdate = false ;
3238 }
3339
40+ // Before entering the begin phase, clear the expiration time.
41+ workInProgress . expirationTime = NoWork ;
42+
3443 switch ( workInProgress . tag ) {
3544 case FunctionalComponent :
3645 const Component = workInProgress . type ;
37- return updateFunctionalComponent (
46+ return updateFunctionComponent (
3847 current ,
3948 workInProgress ,
4049 Component ,
@@ -49,33 +58,47 @@ export function beginWork(current, workInProgress, renderExpirationTime) {
4958 case HostRoot :
5059 return updateHostRoot ( current , workInProgress , renderExpirationTime ) ;
5160 case HostComponent :
52- return updateHostComponent ( current , workInProgress ) ;
61+ return updateHostComponent ( current , workInProgress , renderExpirationTime ) ;
5362 case HostText :
5463 return updateHostText ( current , workInProgress ) ;
5564 case Mode :
56- return updateMode ( current , workInProgress ) ;
65+ return updateMode ( current , workInProgress , renderExpirationTime ) ;
5766 }
5867}
5968
60- export function updateHostRoot ( current , workInProgress , renderExpirationTime ) {
61- let updateQueue = workInProgress . updateQueue ;
62- if ( updateQueue != null ) {
63- let state = processUpdateQueue (
69+ function updateHostRoot ( current , workInProgress , renderExpirationTime ) {
70+ const updateQueue = workInProgress . updateQueue ;
71+ const nextProps = workInProgress . pendingProps ;
72+ const prevState = workInProgress . memoizedState ;
73+ const prevChildren = prevState !== null ? prevState . element : null ;
74+ processUpdateQueue (
75+ current ,
76+ workInProgress ,
77+ updateQueue ,
78+ nextProps ,
79+ null ,
80+ renderExpirationTime ,
81+ ) ;
82+ const nextState = workInProgress . memoizedState ;
83+ const nextChildren = nextState . element ;
84+
85+ if ( nextChildren === prevChildren ) {
86+ return bailoutOnAlreadyFinishedWork (
6487 current ,
6588 workInProgress ,
66- updateQueue ,
67- null ,
68- null ,
6989 renderExpirationTime ,
7090 ) ;
71- reconcileChildren ( current , workInProgress , state . element ) ;
72- workInProgress . memoizedState = state ;
73- return workInProgress . child ;
7491 }
75- return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
92+ reconcileChildren (
93+ current ,
94+ workInProgress ,
95+ nextChildren ,
96+ renderExpirationTime ,
97+ ) ;
98+ return workInProgress . child ;
7699}
77100
78- export function updateFunctionalComponent (
101+ function updateFunctionComponent (
79102 current ,
80103 workInProgress ,
81104 Component ,
@@ -98,12 +121,16 @@ export function updateFunctionalComponent(
98121 }
99122
100123 workInProgress . effectTag |= PerformedWork ;
101- reconcileChildren ( current , workInProgress , nextChildren ) ;
102- workInProgress . memoizedProps = nextProps ;
124+ reconcileChildren (
125+ current ,
126+ workInProgress ,
127+ nextChildren ,
128+ renderExpirationTime ,
129+ ) ;
103130 return workInProgress . child ;
104131}
105132
106- export function updateHostText ( current , workInProgress ) {
133+ function updateHostText ( current , workInProgress ) {
107134 if ( current == null ) {
108135 workInProgress . effectTag |= Placement ;
109136 }
@@ -112,28 +139,23 @@ export function updateHostText(current, workInProgress) {
112139 return null ;
113140}
114141
115- export function updateHostComponent ( current , workInProgress ) {
142+ function updateHostComponent ( current , workInProgress , renderExpirationTime ) {
116143 if ( current == null ) {
117144 workInProgress . effectTag |= Placement ;
118145 }
119146 const memoizedProps = workInProgress . memoizedProps ;
120147 let nextProps = workInProgress . pendingProps || memoizedProps ;
121-
122- if ( nextProps == null || memoizedProps === nextProps ) {
123- return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
124- }
125-
126148 let nextChildren = nextProps . children ;
127- reconcileChildren ( current , workInProgress , nextChildren ) ;
128- workInProgress . memoizedProps = nextProps ;
149+ reconcileChildren (
150+ current ,
151+ workInProgress ,
152+ nextChildren ,
153+ renderExpirationTime ,
154+ ) ;
129155 return workInProgress . child ;
130156}
131157
132- export function updateClassComponent (
133- current ,
134- workInProgress ,
135- renderExpirationTime ,
136- ) {
158+ function updateClassComponent ( current , workInProgress , renderExpirationTime ) {
137159 let shouldUpdate ;
138160 if ( current == null ) {
139161 if ( ! workInProgress . stateNode ) {
@@ -153,7 +175,12 @@ export function updateClassComponent(
153175 renderExpirationTime ,
154176 ) ;
155177 }
156- return finishClassComponent ( current , workInProgress , shouldUpdate ) ;
178+ return finishClassComponent (
179+ current ,
180+ workInProgress ,
181+ shouldUpdate ,
182+ renderExpirationTime ,
183+ ) ;
157184}
158185
159186function updateClassInstance ( current , workInProgress , renderExpirationTime ) {
@@ -191,28 +218,63 @@ function updateClassInstance(current, workInProgress, renderExpirationTime) {
191218 return true ;
192219}
193220
194- function finishClassComponent ( current , workInProgress , shouldUpdate ) {
221+ function finishClassComponent (
222+ current ,
223+ workInProgress ,
224+ shouldUpdate ,
225+ renderExpirationTime ,
226+ ) {
195227 if ( ! shouldUpdate ) {
196- return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
228+ return bailoutOnAlreadyFinishedWork (
229+ current ,
230+ workInProgress ,
231+ renderExpirationTime ,
232+ ) ;
197233 }
198234
199235 const instance = workInProgress . stateNode ;
200236 const nextChildren = instance . render ( ) ;
201237
202238 workInProgress . effectTag |= PerformedWork ;
203- reconcileChildren ( current , workInProgress , nextChildren ) ;
239+ reconcileChildren (
240+ current ,
241+ workInProgress ,
242+ nextChildren ,
243+ renderExpirationTime ,
244+ ) ;
204245 workInProgress . memoizedState = instance . state ;
205- workInProgress . memoizedProps = instance . props ;
206246 return workInProgress . child ;
207247}
208248
209- function bailoutOnAlreadyFinishedWork ( current , workInProgress ) {
210- cloneChildFibers ( current , workInProgress ) ;
211- return workInProgress . child ;
249+ function bailoutOnAlreadyFinishedWork (
250+ current ,
251+ workInProgress ,
252+ renderExpirationTime ,
253+ ) {
254+ // Check if the children have any pending work.
255+ const childExpirationTime = workInProgress . childExpirationTime ;
256+ if (
257+ childExpirationTime === NoWork ||
258+ childExpirationTime > renderExpirationTime
259+ ) {
260+ // The children don't have any work either. We can skip them.
261+ // TODO: Once we add back resuming, we should check if the children are
262+ // a work-in-progress set. If so, we need to transfer their effects.
263+ return null ;
264+ } else {
265+ // This fiber doesn't have work, but its subtree does. Clone the child
266+ // fibers and continue.
267+ cloneChildFibers ( current , workInProgress ) ;
268+ return workInProgress . child ;
269+ }
212270}
213271
214- function reconcileChildren ( current , workInProgress , nextChildren ) {
215- const renderExpirationTime = workInProgress . expirationTime ;
272+ function reconcileChildren (
273+ current ,
274+ workInProgress ,
275+ nextChildren ,
276+ renderExpirationTime ,
277+ ) {
216278 if ( current == null ) {
217279 // If this is a fresh new component that hasn't been rendered yet, we
218280 // won't update its child set by applying minimal side-effects. Instead,
@@ -240,13 +302,14 @@ function reconcileChildren(current, workInProgress, nextChildren) {
240302 }
241303}
242304
243- function updateMode ( current , workInProgress ) {
305+ function updateMode ( current , workInProgress , renderExpirationTime ) {
244306 const nextChildren = workInProgress . pendingProps . children ;
245- if ( nextChildren == null || workInProgress . memoizedProps === nextChildren ) {
246- return bailoutOnAlreadyFinishedWork ( current , workInProgress ) ;
247- }
248- reconcileChildren ( current , workInProgress , nextChildren ) ;
249- workInProgress . memoizedProps = nextChildren ;
307+ reconcileChildren (
308+ current ,
309+ workInProgress ,
310+ nextChildren ,
311+ renderExpirationTime ,
312+ ) ;
250313 return workInProgress . child ;
251314}
252315
0 commit comments