-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ref cleanup function #25686
Add ref cleanup function #25686
Changes from 4 commits
3716c39
be50757
073cec2
b9a8ed7
9d315ab
d68d6e9
ebb8afc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -286,7 +286,33 @@ function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) { | |
|
||
function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) { | ||
const ref = current.ref; | ||
if (ref !== null) { | ||
const refCleanup = current.refCleanup; | ||
|
||
if (refCleanup !== null) { | ||
if (typeof ref === 'function') { | ||
try { | ||
if (shouldProfile(current)) { | ||
try { | ||
startLayoutEffectTimer(); | ||
refCleanup(); | ||
} finally { | ||
recordLayoutEffectDuration(current); | ||
} | ||
} else { | ||
refCleanup(); | ||
} | ||
} catch (error) { | ||
captureCommitPhaseError(current, nearestMountedAncestor, error); | ||
} finally { | ||
// `refCleanup` has been called. Nullify all references to it to prevent double invocation. | ||
current.refCleanup = null; | ||
const finishedWork = current.alternate; | ||
if (finishedWork != null) { | ||
finishedWork.refCleanup = null; | ||
} | ||
} | ||
} | ||
} else if (ref !== null) { | ||
if (typeof ref === 'function') { | ||
let retVal; | ||
try { | ||
|
@@ -1583,14 +1609,9 @@ function commitAttachRef(finishedWork: Fiber) { | |
} else { | ||
retVal = ref(instanceToUse); | ||
} | ||
if (__DEV__) { | ||
if (typeof retVal === 'function') { | ||
console.error( | ||
'Unexpected return value from a callback ref in %s. ' + | ||
'A callback ref should not return a function.', | ||
getComponentNameFromFiber(finishedWork), | ||
); | ||
} | ||
|
||
if (typeof retVal === 'function') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normally it's good to check the type as close to where you get it from the user as possible but it'd probably be ok to do this type check during the cleanup instead. That way there's no extra work on initial mount. The VM has to check the type anyway before calling it upon cleanup. |
||
finishedWork.refCleanup = retVal; | ||
} | ||
} else { | ||
if (__DEV__) { | ||
|
@@ -1609,27 +1630,6 @@ function commitAttachRef(finishedWork: Fiber) { | |
} | ||
} | ||
|
||
function commitDetachRef(current: Fiber) { | ||
const currentRef = current.ref; | ||
if (currentRef !== null) { | ||
if (typeof currentRef === 'function') { | ||
if (shouldProfile(current)) { | ||
try { | ||
startLayoutEffectTimer(); | ||
currentRef(null); | ||
} finally { | ||
recordLayoutEffectDuration(current); | ||
} | ||
} else { | ||
currentRef(null); | ||
} | ||
} else { | ||
// $FlowFixMe unable to narrow type to the non-function case | ||
currentRef.current = null; | ||
} | ||
} | ||
} | ||
|
||
function detachFiberMutation(fiber: Fiber) { | ||
// Cut off the return pointer to disconnect it from the tree. | ||
// This enables us to detect and warn against state updates on an unmounted component. | ||
|
@@ -4450,7 +4450,6 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void { | |
export { | ||
commitPlacement, | ||
commitAttachRef, | ||
commitDetachRef, | ||
invokeLayoutEffectMountInDEV, | ||
invokeLayoutEffectUnmountInDEV, | ||
invokePassiveEffectMountInDEV, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -286,7 +286,33 @@ function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) { | |
|
||
function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) { | ||
const ref = current.ref; | ||
if (ref !== null) { | ||
const refCleanup = current.refCleanup; | ||
|
||
if (refCleanup !== null) { | ||
if (typeof ref === 'function') { | ||
try { | ||
if (shouldProfile(current)) { | ||
try { | ||
startLayoutEffectTimer(); | ||
refCleanup(); | ||
} finally { | ||
recordLayoutEffectDuration(current); | ||
} | ||
} else { | ||
refCleanup(); | ||
} | ||
} catch (error) { | ||
captureCommitPhaseError(current, nearestMountedAncestor, error); | ||
} finally { | ||
// `refCleanup` has been called. Nullify all references to it to prevent double invocation. | ||
current.refCleanup = null; | ||
const finishedWork = current.alternate; | ||
if (finishedWork != null) { | ||
finishedWork.refCleanup = null; | ||
} | ||
} | ||
} | ||
} else if (ref !== null) { | ||
if (typeof ref === 'function') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can place the |
||
let retVal; | ||
try { | ||
|
@@ -1583,14 +1609,9 @@ function commitAttachRef(finishedWork: Fiber) { | |
} else { | ||
retVal = ref(instanceToUse); | ||
} | ||
if (__DEV__) { | ||
if (typeof retVal === 'function') { | ||
console.error( | ||
'Unexpected return value from a callback ref in %s. ' + | ||
'A callback ref should not return a function.', | ||
getComponentNameFromFiber(finishedWork), | ||
); | ||
} | ||
|
||
if (typeof retVal === 'function') { | ||
finishedWork.refCleanup = retVal; | ||
} | ||
} else { | ||
if (__DEV__) { | ||
|
@@ -1609,27 +1630,6 @@ function commitAttachRef(finishedWork: Fiber) { | |
} | ||
} | ||
|
||
function commitDetachRef(current: Fiber) { | ||
const currentRef = current.ref; | ||
if (currentRef !== null) { | ||
if (typeof currentRef === 'function') { | ||
if (shouldProfile(current)) { | ||
try { | ||
startLayoutEffectTimer(); | ||
currentRef(null); | ||
} finally { | ||
recordLayoutEffectDuration(current); | ||
} | ||
} else { | ||
currentRef(null); | ||
} | ||
} else { | ||
// $FlowFixMe unable to narrow type to the non-function case | ||
currentRef.current = null; | ||
} | ||
} | ||
} | ||
|
||
function detachFiberMutation(fiber: Fiber) { | ||
// Cut off the return pointer to disconnect it from the tree. | ||
// This enables us to detect and warn against state updates on an unmounted component. | ||
|
@@ -4450,7 +4450,6 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void { | |
export { | ||
commitPlacement, | ||
commitAttachRef, | ||
commitDetachRef, | ||
invokeLayoutEffectMountInDEV, | ||
invokeLayoutEffectUnmountInDEV, | ||
invokePassiveEffectMountInDEV, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we set
refCleanup
to null? What isfinishedWork
? Is it possible thatfinishedWork
contains a ref that we have not yet detached?