@@ -86,6 +86,16 @@ import {
8686 requestCurrentTime ,
8787 scheduleWork ,
8888} from './ReactFiberScheduler' ;
89+ import {
90+ NoEffect as NoHookEffect ,
91+ UnmountSnapshot ,
92+ UnmountMutation ,
93+ MountMutation ,
94+ UnmountLayout ,
95+ MountLayout ,
96+ UnmountPassive ,
97+ MountPassive ,
98+ } from './ReactHookEffectTags' ;
8999
90100let didWarnAboutUndefinedSnapshotBeforeUpdate : Set < mixed > | null = null ;
91101if ( __DEV__ ) {
@@ -204,6 +214,11 @@ function commitBeforeMutationLifeCycles(
204214 finishedWork : Fiber ,
205215) : void {
206216 switch ( finishedWork . tag ) {
217+ case FunctionComponent :
218+ case ForwardRef : {
219+ commitHookEffectList ( UnmountSnapshot , NoHookEffect , finishedWork ) ;
220+ return ;
221+ }
207222 case ClassComponent : {
208223 if ( finishedWork . effectTag & Snapshot ) {
209224 if ( current !== null ) {
@@ -254,26 +269,39 @@ function commitBeforeMutationLifeCycles(
254269 }
255270}
256271
257- function destroyRemainingEffects ( firstToDestroy , stopAt ) {
258- let effect = firstToDestroy ;
259- do {
260- const destroy = effect . value ;
261- if ( destroy !== null ) {
262- destroy ( ) ;
263- }
264- effect = effect . next ;
265- } while ( effect !== stopAt ) ;
272+ function commitHookEffectList (
273+ unmountTag : number ,
274+ mountTag : number ,
275+ finishedWork : Fiber ,
276+ ) {
277+ const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
278+ let lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
279+ if ( lastEffect !== null ) {
280+ const firstEffect = lastEffect . next ;
281+ let effect = firstEffect ;
282+ do {
283+ if ( ( effect . tag & unmountTag ) !== NoHookEffect ) {
284+ // Unmount
285+ const destroy = effect . destroy ;
286+ effect . destroy = null ;
287+ if ( destroy !== null ) {
288+ destroy ( ) ;
289+ }
290+ }
291+ if ( ( effect . tag & mountTag ) !== NoHookEffect ) {
292+ // Mount
293+ const create = effect . create ;
294+ const destroy = create ( ) ;
295+ effect . destroy = typeof destroy === 'function' ? destroy : null ;
296+ }
297+ effect = effect . next ;
298+ } while ( effect !== firstEffect ) ;
299+ }
266300}
267301
268- function destroyMountedEffects ( current ) {
269- const oldUpdateQueue : FunctionComponentUpdateQueue | null = ( current . updateQueue : any ) ;
270- if ( oldUpdateQueue !== null ) {
271- const oldLastEffect = oldUpdateQueue . lastEffect ;
272- if ( oldLastEffect !== null ) {
273- const oldFirstEffect = oldLastEffect . next ;
274- destroyRemainingEffects ( oldFirstEffect , oldFirstEffect ) ;
275- }
276- }
302+ export function commitPassiveHookEffects ( finishedWork : Fiber ) : void {
303+ commitHookEffectList ( UnmountPassive , NoHookEffect , finishedWork ) ;
304+ commitHookEffectList ( NoHookEffect , MountPassive , finishedWork ) ;
277305}
278306
279307function commitLifeCycles (
@@ -285,98 +313,12 @@ function commitLifeCycles(
285313 switch ( finishedWork . tag ) {
286314 case FunctionComponent :
287315 case ForwardRef : {
288- const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
289- if ( updateQueue !== null ) {
290- // Mount new effects and destroy the old ones by comparing to the
291- // current list of effects. This could be a bit simpler if we avoided
292- // the need to compare to the previous effect list by transferring the
293- // old `destroy` method to the new effect during the render phase.
294- // That's how I originally implemented it, but it requires an additional
295- // field on the effect object.
296- //
297- // This supports removing effects from the end of the list. If we adopt
298- // the constraint that hooks are append only, that would also save a bit
299- // on code size.
300- const newLastEffect = updateQueue . lastEffect ;
301- if ( newLastEffect !== null ) {
302- const newFirstEffect = newLastEffect . next ;
303- let oldLastEffect = null ;
304- if ( current !== null ) {
305- const oldUpdateQueue : FunctionComponentUpdateQueue | null = ( current . updateQueue : any ) ;
306- if ( oldUpdateQueue !== null ) {
307- oldLastEffect = oldUpdateQueue . lastEffect ;
308- }
309- }
310- if ( oldLastEffect !== null ) {
311- const oldFirstEffect = oldLastEffect . next ;
312- let newEffect = newFirstEffect ;
313- let oldEffect = oldFirstEffect ;
314-
315- // Before mounting the new effects, unmount all the old ones.
316- do {
317- if ( oldEffect !== null ) {
318- if ( newEffect . inputs !== oldEffect . inputs ) {
319- const destroy = oldEffect . value ;
320- if ( destroy !== null ) {
321- destroy ( ) ;
322- }
323- }
324- oldEffect = oldEffect . next ;
325- if ( oldEffect === oldFirstEffect ) {
326- oldEffect = null ;
327- }
328- }
329- newEffect = newEffect . next ;
330- } while ( newEffect !== newFirstEffect ) ;
331-
332- // Unmount any remaining effects in the old list that do not
333- // appear in the new one.
334- if ( oldEffect !== null ) {
335- destroyRemainingEffects ( oldEffect , oldFirstEffect ) ;
336- }
337-
338- // Now loop through the list again to mount the new effects
339- oldEffect = oldFirstEffect ;
340- do {
341- const create = newEffect . value ;
342- if ( oldEffect !== null ) {
343- if ( newEffect . inputs !== oldEffect . inputs ) {
344- const newDestroy = create ( ) ;
345- newEffect . value =
346- typeof newDestroy === 'function' ? newDestroy : null ;
347- } else {
348- newEffect . value = oldEffect . value ;
349- }
350- oldEffect = oldEffect . next ;
351- if ( oldEffect === oldFirstEffect ) {
352- oldEffect = null ;
353- }
354- } else {
355- const newDestroy = create ( ) ;
356- newEffect . value =
357- typeof newDestroy === 'function' ? newDestroy : null ;
358- }
359- newEffect = newEffect . next ;
360- } while ( newEffect !== newFirstEffect ) ;
361- } else {
362- let newEffect = newFirstEffect ;
363- do {
364- const create = newEffect . value ;
365- const newDestroy = create ( ) ;
366- newEffect . value =
367- typeof newDestroy === 'function' ? newDestroy : null ;
368- newEffect = newEffect . next ;
369- } while ( newEffect !== newFirstEffect ) ;
370- }
371- } else if ( current !== null ) {
372- // There are no effects, which means all current effects must
373- // be destroyed
374- destroyMountedEffects ( current ) ;
375- }
376-
377- const callbackList = updateQueue . callbackList ;
316+ commitHookEffectList ( UnmountLayout , MountLayout , finishedWork ) ;
317+ const newUpdateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
318+ if ( newUpdateQueue !== null ) {
319+ const callbackList = newUpdateQueue . callbackList ;
378320 if ( callbackList !== null ) {
379- updateQueue . callbackList = null ;
321+ newUpdateQueue . callbackList = null ;
380322 for ( let i = 0 ; i < callbackList . length ; i ++ ) {
381323 const update = callbackList [ i ] ;
382324 // Assume this is non-null, since otherwise it would not be part
@@ -386,10 +328,6 @@ function commitLifeCycles(
386328 callback ( ) ;
387329 }
388330 }
389- } else if ( current !== null ) {
390- // There are no effects, which means all current effects must
391- // be destroyed
392- destroyMountedEffects ( current ) ;
393331 }
394332 break ;
395333 }
@@ -656,7 +594,7 @@ function commitUnmount(current: Fiber): void {
656594 const firstEffect = lastEffect . next ;
657595 let effect = firstEffect ;
658596 do {
659- const destroy = effect . value ;
597+ const destroy = effect . destroy ;
660598 if ( destroy !== null ) {
661599 safelyCallDestroy ( current , destroy ) ;
662600 }
@@ -1039,11 +977,24 @@ function commitDeletion(current: Fiber): void {
1039977
1040978function commitWork ( current : Fiber | null , finishedWork : Fiber ) : void {
1041979 if ( ! supportsMutation ) {
980+ switch ( finishedWork . tag ) {
981+ case FunctionComponent :
982+ case ForwardRef : {
983+ commitHookEffectList ( UnmountMutation , MountMutation , finishedWork ) ;
984+ return ;
985+ }
986+ }
987+
1042988 commitContainer ( finishedWork ) ;
1043989 return ;
1044990 }
1045991
1046992 switch ( finishedWork . tag ) {
993+ case FunctionComponent :
994+ case ForwardRef : {
995+ commitHookEffectList ( UnmountMutation , MountMutation , finishedWork ) ;
996+ return ;
997+ }
1047998 case ClassComponent : {
1048999 return ;
10491000 }
0 commit comments