@@ -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,68 @@ export function commitHookEffectListMount(
146153
147154 // Mount
148155 let destroy ;
156+ if ( enableUseResourceEffectHook ) {
157+ if ( effect . kind === ResourceEffectIdentityKind ) {
158+ if ( __DEV__ ) {
159+ effect . resource = runWithFiberInDEV (
160+ finishedWork ,
161+ callCreateInDEV ,
162+ effect ,
163+ ) ;
164+ if ( effect . 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 . resource ,
169+ ) ;
170+ }
171+ } else {
172+ effect . resource = effect . create ( ) ;
173+ }
174+ if ( effect . next . kind === ResourceEffectUpdateKind ) {
175+ effect . next . resource = effect . resource ;
176+ } else {
177+ if ( __DEV__ ) {
178+ console . error (
179+ 'Found identity effect without an update effect. This is a bug in React.' ,
180+ ) ;
181+ }
182+ }
183+ destroy = effect . destroy ;
184+ }
185+ if ( effect . kind === ResourceEffectUpdateKind ) {
186+ if (
187+ // We don't want to fire updates on remount during Activity
188+ ( flags & HookHasEffect ) > 0 &&
189+ typeof effect . update === 'function' &&
190+ effect . resource != null
191+ ) {
192+ // TODO(@poteto) what about multiple updates?
193+ effect . update ( effect . resource ) ;
194+ }
195+ }
196+ }
149197 if ( __DEV__ ) {
150198 if ( ( flags & HookInsertion ) !== NoHookEffect ) {
151199 setIsRunningInsertionEffect ( true ) ;
152200 }
153- destroy = runWithFiberInDEV ( finishedWork , callCreateInDEV , effect ) ;
201+ if ( effect . kind === SimpleEffectKind ) {
202+ destroy = runWithFiberInDEV (
203+ finishedWork ,
204+ callCreateInDEV ,
205+ effect ,
206+ ) ;
207+ }
154208 if ( ( flags & HookInsertion ) !== NoHookEffect ) {
155209 setIsRunningInsertionEffect ( false ) ;
156210 }
157211 } else {
158- const create = effect . create ;
159- const inst = effect . inst ;
160- destroy = create ( ) ;
161- inst . destroy = destroy ;
212+ if ( effect . kind === SimpleEffectKind ) {
213+ const create = effect . create ;
214+ const inst = effect . inst ;
215+ destroy = create ( ) ;
216+ inst . destroy = destroy ;
217+ }
162218 }
163219
164220 if ( enableSchedulingProfiler ) {
@@ -176,6 +232,11 @@ export function commitHookEffectListMount(
176232 hookName = 'useLayoutEffect' ;
177233 } else if ( ( effect . tag & HookInsertion ) !== NoFlags ) {
178234 hookName = 'useInsertionEffect' ;
235+ } else if (
236+ enableUseResourceEffectHook &&
237+ effect . kind === ResourceEffectIdentityKind
238+ ) {
239+ hookName = 'useResourceEffect' ;
179240 } else {
180241 hookName = 'useEffect' ;
181242 }
@@ -244,9 +305,34 @@ export function commitHookEffectListUnmount(
244305 if ( ( effect . tag & flags ) === flags ) {
245306 // Unmount
246307 const inst = effect . inst ;
308+ if (
309+ enableUseResourceEffectHook &&
310+ effect . kind === ResourceEffectIdentityKind &&
311+ effect . resource != null
312+ ) {
313+ inst . destroy = effect . destroy ;
314+ }
247315 const destroy = inst . destroy ;
248316 if ( destroy !== undefined ) {
249317 inst . destroy = undefined ;
318+ let resource ;
319+ if ( enableUseResourceEffectHook ) {
320+ if ( effect . kind === ResourceEffectIdentityKind ) {
321+ resource = effect . resource ;
322+ effect . resource = null ;
323+ // TODO(@poteto) very sketchy
324+ if ( effect . next . kind === ResourceEffectUpdateKind ) {
325+ effect . next . resource = null ;
326+ effect . next . update = undefined ;
327+ } else {
328+ if ( __DEV__ ) {
329+ console . error (
330+ 'Found identity effect without an update effect. This is a bug in React.' ,
331+ ) ;
332+ }
333+ }
334+ }
335+ }
250336 if ( enableSchedulingProfiler ) {
251337 if ( ( flags & HookPassive ) !== NoHookEffect ) {
252338 markComponentPassiveEffectUnmountStarted ( finishedWork ) ;
@@ -260,7 +346,16 @@ export function commitHookEffectListUnmount(
260346 setIsRunningInsertionEffect ( true ) ;
261347 }
262348 }
263- safelyCallDestroy ( finishedWork , nearestMountedAncestor , destroy ) ;
349+ if ( enableUseResourceEffectHook ) {
350+ safelyCallDestroyWithResource (
351+ finishedWork ,
352+ nearestMountedAncestor ,
353+ destroy ,
354+ resource ,
355+ ) ;
356+ } else {
357+ safelyCallDestroy ( finishedWork , nearestMountedAncestor , destroy ) ;
358+ }
264359 if ( __DEV__ ) {
265360 if ( ( flags & HookInsertion ) !== NoHookEffect ) {
266361 setIsRunningInsertionEffect ( false ) ;
@@ -895,6 +990,30 @@ function safelyCallDestroy(
895990 }
896991}
897992
993+ function safelyCallDestroyWithResource (
994+ current : Fiber ,
995+ nearestMountedAncestor : Fiber | null ,
996+ destroy : mixed => void ,
997+ resource : mixed ,
998+ ) {
999+ const destroy_ = resource == null ? destroy : destroy . bind ( null , resource ) ;
1000+ if ( __DEV__ ) {
1001+ runWithFiberInDEV (
1002+ current ,
1003+ callDestroyInDEV ,
1004+ current ,
1005+ nearestMountedAncestor ,
1006+ destroy_ ,
1007+ ) ;
1008+ } else {
1009+ try {
1010+ destroy_ ( ) ;
1011+ } catch ( error ) {
1012+ captureCommitPhaseError ( current , nearestMountedAncestor , error ) ;
1013+ }
1014+ }
1015+ }
1016+
8981017function commitProfiler(
8991018 finishedWork: Fiber,
9001019 current: Fiber | null,
0 commit comments