@@ -18,6 +18,7 @@ import {
18
18
enableProfilerNestedUpdatePhase ,
19
19
enableSchedulingProfiler ,
20
20
enableScopeAPI ,
21
+ enableUseResourceEffectHook ,
21
22
} from 'shared/ReactFeatureFlags' ;
22
23
import {
23
24
ClassComponent ,
@@ -49,6 +50,7 @@ import {
49
50
Layout as HookLayout ,
50
51
Insertion as HookInsertion ,
51
52
Passive as HookPassive ,
53
+ HasEffect as HookHasEffect ,
52
54
} from './ReactHookEffectTags' ;
53
55
import { didWarnAboutReassigningProps } from './ReactFiberBeginWork' ;
54
56
import {
@@ -70,6 +72,11 @@ import {
70
72
} from './ReactFiberCallUserSpace' ;
71
73
72
74
import { runWithFiberInDEV } from './ReactCurrentFiber' ;
75
+ import {
76
+ ResourceEffectIdentityKind ,
77
+ ResourceEffectUpdateKind ,
78
+ SimpleEffectKind ,
79
+ } from './ReactFiberHooks' ;
73
80
74
81
function shouldProfile ( current : Fiber ) : boolean {
75
82
return (
@@ -146,19 +153,63 @@ export function commitHookEffectListMount(
146
153
147
154
// Mount
148
155
let destroy ;
156
+ if ( enableUseResourceEffectHook ) {
157
+ if ( effect . kind === ResourceEffectIdentityKind ) {
158
+ if ( __DEV__ ) {
159
+ effect . inst . resource = runWithFiberInDEV (
160
+ finishedWork ,
161
+ callCreateInDEV ,
162
+ effect ,
163
+ ) ;
164
+ if ( effect . inst . resource == null ) {
165
+ console . error (
166
+ 'useResourceEffect must provide a callback which returns a resource. ' +
167
+ 'If a managed resource is not needed here, use useEffect. Received %s' ,
168
+ effect . inst . resource ,
169
+ ) ;
170
+ }
171
+ } else {
172
+ effect . inst . resource = effect . create ( ) ;
173
+ }
174
+ destroy = effect . inst . destroy ;
175
+ }
176
+ if ( effect . kind === ResourceEffectUpdateKind ) {
177
+ if (
178
+ // We don't want to fire updates on remount during Activity
179
+ ( flags & HookHasEffect ) > 0 &&
180
+ typeof effect . update === 'function' &&
181
+ effect . inst . resource != null
182
+ ) {
183
+ // TODO(@poteto) what about multiple updates?
184
+ if ( __DEV__ ) {
185
+ runWithFiberInDEV ( finishedWork , callCreateInDEV , effect ) ;
186
+ } else {
187
+ effect . update ( effect . inst . resource ) ;
188
+ }
189
+ }
190
+ }
191
+ }
149
192
if ( __DEV__ ) {
150
193
if ( ( flags & HookInsertion ) !== NoHookEffect ) {
151
194
setIsRunningInsertionEffect ( true ) ;
152
195
}
153
- destroy = runWithFiberInDEV ( finishedWork , callCreateInDEV , effect ) ;
196
+ if ( effect . kind === SimpleEffectKind ) {
197
+ destroy = runWithFiberInDEV (
198
+ finishedWork ,
199
+ callCreateInDEV ,
200
+ effect ,
201
+ ) ;
202
+ }
154
203
if ( ( flags & HookInsertion ) !== NoHookEffect ) {
155
204
setIsRunningInsertionEffect ( false ) ;
156
205
}
157
206
} else {
158
- const create = effect . create ;
159
- const inst = effect . inst ;
160
- destroy = create ( ) ;
161
- inst . destroy = destroy ;
207
+ if ( effect . kind === SimpleEffectKind ) {
208
+ const create = effect . create ;
209
+ const inst = effect . inst ;
210
+ destroy = create ( ) ;
211
+ inst . destroy = destroy ;
212
+ }
162
213
}
163
214
164
215
if ( enableSchedulingProfiler ) {
@@ -176,6 +227,11 @@ export function commitHookEffectListMount(
176
227
hookName = 'useLayoutEffect' ;
177
228
} else if ( ( effect . tag & HookInsertion ) !== NoFlags ) {
178
229
hookName = 'useInsertionEffect' ;
230
+ } else if (
231
+ enableUseResourceEffectHook &&
232
+ effect . kind === ResourceEffectIdentityKind
233
+ ) {
234
+ hookName = 'useResourceEffect' ;
179
235
} else {
180
236
hookName = 'useEffect' ;
181
237
}
@@ -246,7 +302,9 @@ export function commitHookEffectListUnmount(
246
302
const inst = effect . inst ;
247
303
const destroy = inst . destroy ;
248
304
if ( destroy !== undefined ) {
249
- inst . destroy = undefined ;
305
+ if ( effect . kind === SimpleEffectKind ) {
306
+ inst . destroy = undefined ;
307
+ }
250
308
if ( enableSchedulingProfiler ) {
251
309
if ( ( flags & HookPassive ) !== NoHookEffect ) {
252
310
markComponentPassiveEffectUnmountStarted ( finishedWork ) ;
@@ -260,7 +318,40 @@ export function commitHookEffectListUnmount(
260
318
setIsRunningInsertionEffect ( true ) ;
261
319
}
262
320
}
263
- safelyCallDestroy ( finishedWork , nearestMountedAncestor , destroy ) ;
321
+ if ( enableUseResourceEffectHook ) {
322
+ if (
323
+ effect . kind === ResourceEffectIdentityKind &&
324
+ effect . inst . resource != null
325
+ ) {
326
+ safelyCallDestroyWithResource (
327
+ finishedWork ,
328
+ nearestMountedAncestor ,
329
+ destroy ,
330
+ effect . inst . resource ,
331
+ ) ;
332
+ if ( effect . next . kind === ResourceEffectUpdateKind ) {
333
+ effect . next . update = undefined ;
334
+ } else {
335
+ if ( __DEV__ ) {
336
+ console . error (
337
+ 'Expected a ResourceEffectUpdateKind to follow ResourceEffectIdentityKind, ' +
338
+ 'got %s. This is a bug in React.' ,
339
+ effect . next . kind ,
340
+ ) ;
341
+ }
342
+ }
343
+ effect . inst . resource = null ;
344
+ }
345
+ if ( effect . kind === SimpleEffectKind ) {
346
+ safelyCallDestroy (
347
+ finishedWork ,
348
+ nearestMountedAncestor ,
349
+ destroy ,
350
+ ) ;
351
+ }
352
+ } else {
353
+ safelyCallDestroy ( finishedWork , nearestMountedAncestor , destroy ) ;
354
+ }
264
355
if ( __DEV__ ) {
265
356
if ( ( flags & HookInsertion ) !== NoHookEffect ) {
266
357
setIsRunningInsertionEffect ( false ) ;
@@ -895,6 +986,30 @@ function safelyCallDestroy(
895
986
}
896
987
}
897
988
989
+ function safelyCallDestroyWithResource (
990
+ current : Fiber ,
991
+ nearestMountedAncestor : Fiber | null ,
992
+ destroy : mixed => void ,
993
+ resource : mixed ,
994
+ ) {
995
+ const destroy_ = resource == null ? destroy : destroy . bind ( null , resource ) ;
996
+ if ( __DEV__ ) {
997
+ runWithFiberInDEV (
998
+ current ,
999
+ callDestroyInDEV ,
1000
+ current ,
1001
+ nearestMountedAncestor ,
1002
+ destroy_ ,
1003
+ ) ;
1004
+ } else {
1005
+ try {
1006
+ destroy_ ( ) ;
1007
+ } catch ( error ) {
1008
+ captureCommitPhaseError ( current , nearestMountedAncestor , error ) ;
1009
+ }
1010
+ }
1011
+ }
1012
+
898
1013
function commitProfiler(
899
1014
finishedWork: Fiber,
900
1015
current: Fiber | null,
0 commit comments