diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js
index 687e62de976c7..8e8636d3b17a6 100644
--- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js
+++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js
@@ -194,14 +194,41 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber) {
if (ref !== null) {
if (typeof ref === 'function') {
if (__DEV__) {
- invokeGuardedCallback(null, ref, null, null);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ current.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ invokeGuardedCallback(null, ref, null, null);
+ } finally {
+ recordLayoutEffectDuration(current);
+ }
+ } else {
+ invokeGuardedCallback(null, ref, null, null);
+ }
+
if (hasCaughtError()) {
const refError = clearCaughtError();
captureCommitPhaseError(current, nearestMountedAncestor, refError);
}
} else {
try {
- ref(null);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ current.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ ref(null);
+ } finally {
+ recordLayoutEffectDuration(current);
+ }
+ } else {
+ ref(null);
+ }
} catch (refError) {
captureCommitPhaseError(current, nearestMountedAncestor, refError);
}
@@ -965,7 +992,20 @@ function commitAttachRef(finishedWork: Fiber) {
instanceToUse = instance;
}
if (typeof ref === 'function') {
- ref(instanceToUse);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ finishedWork.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ ref(instanceToUse);
+ } finally {
+ recordLayoutEffectDuration(finishedWork);
+ }
+ } else {
+ ref(instanceToUse);
+ }
} else {
if (__DEV__) {
if (!ref.hasOwnProperty('current')) {
@@ -986,7 +1026,20 @@ function commitDetachRef(current: Fiber) {
const currentRef = current.ref;
if (currentRef !== null) {
if (typeof currentRef === 'function') {
- currentRef(null);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ current.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ currentRef(null);
+ } finally {
+ recordLayoutEffectDuration(current);
+ }
+ } else {
+ currentRef(null);
+ }
} else {
currentRef.current = null;
}
diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js
index e094e5bd9b5a8..3c8c544426e39 100644
--- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js
+++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js
@@ -180,14 +180,41 @@ function safelyDetachRef(current: Fiber) {
if (ref !== null) {
if (typeof ref === 'function') {
if (__DEV__) {
- invokeGuardedCallback(null, ref, null, null);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ current.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ invokeGuardedCallback(null, ref, null, null);
+ } finally {
+ recordLayoutEffectDuration(current);
+ }
+ } else {
+ invokeGuardedCallback(null, ref, null, null);
+ }
+
if (hasCaughtError()) {
const refError = clearCaughtError();
captureCommitPhaseError(current, refError);
}
} else {
try {
- ref(null);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ current.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ ref(null);
+ } finally {
+ recordLayoutEffectDuration(current);
+ }
+ } else {
+ ref(null);
+ }
} catch (refError) {
captureCommitPhaseError(current, refError);
}
@@ -832,7 +859,20 @@ function commitAttachRef(finishedWork: Fiber) {
instanceToUse = instance;
}
if (typeof ref === 'function') {
- ref(instanceToUse);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ finishedWork.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ ref(instanceToUse);
+ } finally {
+ recordLayoutEffectDuration(finishedWork);
+ }
+ } else {
+ ref(instanceToUse);
+ }
} else {
if (__DEV__) {
if (!ref.hasOwnProperty('current')) {
@@ -853,7 +893,20 @@ function commitDetachRef(current: Fiber) {
const currentRef = current.ref;
if (currentRef !== null) {
if (typeof currentRef === 'function') {
- currentRef(null);
+ if (
+ enableProfilerTimer &&
+ enableProfilerCommitHooks &&
+ current.mode & ProfileMode
+ ) {
+ try {
+ startLayoutEffectTimer();
+ currentRef(null);
+ } finally {
+ recordLayoutEffectDuration(current);
+ }
+ } else {
+ currentRef(null);
+ }
} else {
currentRef.current = null;
}
diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js
index 180eb81b964bf..73812de49a3b0 100644
--- a/packages/react/src/__tests__/ReactProfiler-test.internal.js
+++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js
@@ -1491,6 +1491,61 @@ describe('Profiler', () => {
expect(call[4]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events
});
+ it('should include time spent in ref callbacks', () => {
+ const callback = jest.fn();
+
+ const refSetter = ref => {
+ if (ref !== null) {
+ Scheduler.unstable_advanceTime(10);
+ } else {
+ Scheduler.unstable_advanceTime(100);
+ }
+ };
+
+ class ClassComponent extends React.Component {
+ render() {
+ return null;
+ }
+ }
+
+ const Component = () => {
+ Scheduler.unstable_advanceTime(1000);
+ return ;
+ };
+
+ Scheduler.unstable_advanceTime(1);
+
+ const renderer = ReactTestRenderer.create(
+
+
+ ,
+ );
+
+ expect(callback).toHaveBeenCalledTimes(1);
+
+ let call = callback.mock.calls[0];
+
+ expect(call).toHaveLength(enableSchedulerTracing ? 5 : 4);
+ expect(call[0]).toBe('root');
+ expect(call[1]).toBe('mount');
+ expect(call[2]).toBe(10); // durations
+ expect(call[3]).toBe(1001); // commit start time (before mutations or effects)
+
+ callback.mockClear();
+
+ renderer.update();
+
+ expect(callback).toHaveBeenCalledTimes(1);
+
+ call = callback.mock.calls[0];
+
+ expect(call).toHaveLength(enableSchedulerTracing ? 5 : 4);
+ expect(call[0]).toBe('root');
+ expect(call[1]).toBe('update');
+ expect(call[2]).toBe(100); // durations
+ expect(call[3]).toBe(1011); // commit start time (before mutations or effects)
+ });
+
it('should bubble time spent in layout effects to higher profilers', () => {
const callback = jest.fn();