@@ -18,6 +18,7 @@ import {
1818 enableProfilerNestedUpdatePhase ,
1919 enableSchedulingProfiler ,
2020 enableScopeAPI ,
21+ enableUseResourceEffectHook ,
2122} from 'shared/ReactFeatureFlags' ;
2223import {
2324 ClassComponent ,
@@ -49,6 +50,7 @@ import {
4950 Layout as HookLayout ,
5051 Insertion as HookInsertion ,
5152 Passive as HookPassive ,
53+ HasEffect as HookHasEffect ,
5254} from './ReactHookEffectTags' ;
5355import { didWarnAboutReassigningProps } from './ReactFiberBeginWork' ;
5456import {
@@ -70,6 +72,11 @@ import {
7072} from './ReactFiberCallUserSpace' ;
7173
7274import { runWithFiberInDEV } from './ReactCurrentFiber' ;
75+ import {
76+ ResourceEffectIdentityKind ,
77+ ResourceEffectUpdateKind ,
78+ SimpleEffectKind ,
79+ } from './ReactFiberHooks' ;
7380
7481function shouldProfile ( current : Fiber ) : boolean {
7582 return (
@@ -146,19 +153,56 @@ export function commitHookEffectListMount(
146153
147154 // Mount
148155 let destroy ;
156+ if ( enableUseResourceEffectHook ) {
157+ if ( effect . kind === ResourceEffectIdentityKind ) {
158+ effect . resource = effect . create ( ) ;
159+ if ( __DEV__ ) {
160+ if ( effect . resource == null ) {
161+ console . error (
162+ 'useResourceEffect must provide a callback which returns a resource. ' +
163+ 'If a managed resource is not needed here, use useEffect. Received %s' ,
164+ effect . resource ,
165+ ) ;
166+ }
167+ }
168+ if ( effect . next . kind === ResourceEffectUpdateKind ) {
169+ effect . next . resource = effect . resource ;
170+ }
171+ destroy = effect . destroy ;
172+ }
173+ if ( effect . kind === ResourceEffectUpdateKind ) {
174+ if (
175+ // We don't want to fire updates on remount during Activity
176+ ( flags & HookHasEffect ) > 0 &&
177+ typeof effect . update === 'function' &&
178+ effect . resource != null
179+ ) {
180+ // TODO(@poteto) what about multiple updates?
181+ effect . update ( effect . resource ) ;
182+ }
183+ }
184+ }
149185 if ( __DEV__ ) {
150186 if ( ( flags & HookInsertion ) !== NoHookEffect ) {
151187 setIsRunningInsertionEffect ( true ) ;
152188 }
153- destroy = runWithFiberInDEV ( finishedWork , callCreateInDEV , effect ) ;
189+ if ( effect . kind === SimpleEffectKind ) {
190+ destroy = runWithFiberInDEV (
191+ finishedWork ,
192+ callCreateInDEV ,
193+ effect ,
194+ ) ;
195+ }
154196 if ( ( flags & HookInsertion ) !== NoHookEffect ) {
155197 setIsRunningInsertionEffect ( false ) ;
156198 }
157199 } else {
158- const create = effect . create ;
159- const inst = effect . inst ;
160- destroy = create ( ) ;
161- inst . destroy = destroy ;
200+ if ( effect . kind === SimpleEffectKind ) {
201+ const create = effect . create ;
202+ const inst = effect . inst ;
203+ destroy = create ( ) ;
204+ inst . destroy = destroy ;
205+ }
162206 }
163207
164208 if ( enableSchedulingProfiler ) {
@@ -176,6 +220,11 @@ export function commitHookEffectListMount(
176220 hookName = 'useLayoutEffect' ;
177221 } else if ( ( effect . tag & HookInsertion ) !== NoFlags ) {
178222 hookName = 'useInsertionEffect' ;
223+ } else if (
224+ enableUseResourceEffectHook &&
225+ effect . kind === ResourceEffectIdentityKind
226+ ) {
227+ hookName = 'useResourceEffect' ;
179228 } else {
180229 hookName = 'useEffect' ;
181230 }
@@ -244,9 +293,28 @@ export function commitHookEffectListUnmount(
244293 if ( ( effect . tag & flags ) === flags ) {
245294 // Unmount
246295 const inst = effect . inst ;
296+ if (
297+ enableUseResourceEffectHook &&
298+ effect . kind === ResourceEffectIdentityKind &&
299+ effect . resource != null
300+ ) {
301+ inst . destroy = effect . destroy ;
302+ }
247303 const destroy = inst . destroy ;
248304 if ( destroy !== undefined ) {
249305 inst . destroy = undefined ;
306+ let resource ;
307+ if ( enableUseResourceEffectHook ) {
308+ if ( effect . kind === ResourceEffectIdentityKind ) {
309+ resource = effect . resource ;
310+ effect . resource = null ;
311+ // TODO(@poteto) very sketchy
312+ if ( effect . next . kind === ResourceEffectUpdateKind ) {
313+ effect . next . resource = null ;
314+ effect . next . update = undefined ;
315+ }
316+ }
317+ }
250318 if ( enableSchedulingProfiler ) {
251319 if ( ( flags & HookPassive ) !== NoHookEffect ) {
252320 markComponentPassiveEffectUnmountStarted ( finishedWork ) ;
@@ -260,7 +328,16 @@ export function commitHookEffectListUnmount(
260328 setIsRunningInsertionEffect ( true ) ;
261329 }
262330 }
263- safelyCallDestroy ( finishedWork , nearestMountedAncestor , destroy ) ;
331+ if ( enableUseResourceEffectHook ) {
332+ safelyCallDestroyWithResource (
333+ finishedWork ,
334+ nearestMountedAncestor ,
335+ destroy ,
336+ resource ,
337+ ) ;
338+ } else {
339+ safelyCallDestroy ( finishedWork , nearestMountedAncestor , destroy ) ;
340+ }
264341 if ( __DEV__ ) {
265342 if ( ( flags & HookInsertion ) !== NoHookEffect ) {
266343 setIsRunningInsertionEffect ( false ) ;
@@ -895,6 +972,30 @@ function safelyCallDestroy(
895972 }
896973}
897974
975+ function safelyCallDestroyWithResource (
976+ current : Fiber ,
977+ nearestMountedAncestor : Fiber | null ,
978+ destroy : mixed => void ,
979+ resource : mixed ,
980+ ) {
981+ const destroy_ = resource == null ? destroy : destroy . bind ( null , resource ) ;
982+ if ( __DEV__ ) {
983+ runWithFiberInDEV (
984+ current ,
985+ callDestroyInDEV ,
986+ current ,
987+ nearestMountedAncestor ,
988+ destroy_ ,
989+ ) ;
990+ } else {
991+ try {
992+ destroy_ ( ) ;
993+ } catch ( error ) {
994+ captureCommitPhaseError ( current , nearestMountedAncestor , error ) ;
995+ }
996+ }
997+ }
998+
898999function commitProfiler(
8991000 finishedWork: Fiber,
9001001 current: Fiber | null,
0 commit comments