@@ -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,56 @@ export function commitHookEffectListMount(
146
153
147
154
// Mount
148
155
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
+ }
149
185
if ( __DEV__ ) {
150
186
if ( ( flags & HookInsertion ) !== NoHookEffect ) {
151
187
setIsRunningInsertionEffect ( true ) ;
152
188
}
153
- destroy = runWithFiberInDEV ( finishedWork , callCreateInDEV , effect ) ;
189
+ if ( effect . kind === SimpleEffectKind ) {
190
+ destroy = runWithFiberInDEV (
191
+ finishedWork ,
192
+ callCreateInDEV ,
193
+ effect ,
194
+ ) ;
195
+ }
154
196
if ( ( flags & HookInsertion ) !== NoHookEffect ) {
155
197
setIsRunningInsertionEffect ( false ) ;
156
198
}
157
199
} 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
+ }
162
206
}
163
207
164
208
if ( enableSchedulingProfiler ) {
@@ -176,6 +220,11 @@ export function commitHookEffectListMount(
176
220
hookName = 'useLayoutEffect' ;
177
221
} else if ( ( effect . tag & HookInsertion ) !== NoFlags ) {
178
222
hookName = 'useInsertionEffect' ;
223
+ } else if (
224
+ enableUseResourceEffectHook &&
225
+ effect . kind === ResourceEffectIdentityKind
226
+ ) {
227
+ hookName = 'useResourceEffect' ;
179
228
} else {
180
229
hookName = 'useEffect' ;
181
230
}
@@ -244,9 +293,28 @@ export function commitHookEffectListUnmount(
244
293
if ( ( effect . tag & flags ) === flags ) {
245
294
// Unmount
246
295
const inst = effect . inst ;
296
+ if (
297
+ enableUseResourceEffectHook &&
298
+ effect . kind === ResourceEffectIdentityKind &&
299
+ effect . resource != null
300
+ ) {
301
+ inst . destroy = effect . destroy ;
302
+ }
247
303
const destroy = inst . destroy ;
248
304
if ( destroy !== undefined ) {
249
305
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
+ }
250
318
if ( enableSchedulingProfiler ) {
251
319
if ( ( flags & HookPassive ) !== NoHookEffect ) {
252
320
markComponentPassiveEffectUnmountStarted ( finishedWork ) ;
@@ -260,7 +328,16 @@ export function commitHookEffectListUnmount(
260
328
setIsRunningInsertionEffect ( true ) ;
261
329
}
262
330
}
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
+ }
264
341
if ( __DEV__ ) {
265
342
if ( ( flags & HookInsertion ) !== NoHookEffect ) {
266
343
setIsRunningInsertionEffect ( false ) ;
@@ -895,6 +972,30 @@ function safelyCallDestroy(
895
972
}
896
973
}
897
974
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
+
898
999
function commitProfiler(
899
1000
finishedWork: Fiber,
900
1001
current: Fiber | null,
0 commit comments