diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js
index a272da942e665..dff1dc5bc0905 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.js
@@ -1007,6 +1007,8 @@ function updateProfiler(
}
function markRef(current: Fiber | null, workInProgress: Fiber) {
+ // TODO: This is also where we should check the type of the ref and error if
+ // an invalid one is passed, instead of during child reconcilation.
const ref = workInProgress.ref;
if (
(current === null && ref !== null) ||
@@ -3531,7 +3533,7 @@ function updateScopeComponent(
) {
const nextProps = workInProgress.pendingProps;
const nextChildren = nextProps.children;
-
+ markRef(current, workInProgress);
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js
index 639cec6cbf0d5..a2daff05de72e 100644
--- a/packages/react-reconciler/src/ReactFiberCompleteWork.js
+++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js
@@ -75,8 +75,6 @@ import {
} from './ReactWorkTags';
import {NoMode, ConcurrentMode, ProfileMode} from './ReactTypeOfMode';
import {
- Ref,
- RefStatic,
Placement,
Update,
Visibility,
@@ -186,10 +184,6 @@ function markUpdate(workInProgress: Fiber) {
workInProgress.flags |= Update;
}
-function markRef(workInProgress: Fiber) {
- workInProgress.flags |= Ref | RefStatic;
-}
-
/**
* In persistent mode, return whether this update needs to clone the subtree.
*/
@@ -1083,9 +1077,6 @@ function completeWork(
// @TODO refactor this block to create the instance here in complete
// phase if we are not hydrating.
markUpdate(workInProgress);
- if (workInProgress.ref !== null) {
- markRef(workInProgress);
- }
if (nextResource !== null) {
// This is a Hoistable Resource
@@ -1120,9 +1111,6 @@ function completeWork(
// and require an update
markUpdate(workInProgress);
}
- if (current.ref !== workInProgress.ref) {
- markRef(workInProgress);
- }
if (nextResource !== null) {
// This is a Hoistable Resource
// This must come at the very end of the complete phase.
@@ -1194,10 +1182,6 @@ function completeWork(
renderLanes,
);
}
-
- if (current.ref !== workInProgress.ref) {
- markRef(workInProgress);
- }
} else {
if (!newProps) {
if (workInProgress.stateNode === null) {
@@ -1232,11 +1216,6 @@ function completeWork(
workInProgress.stateNode = instance;
markUpdate(workInProgress);
}
-
- if (workInProgress.ref !== null) {
- // If there is a ref on a host node we need to schedule a callback
- markRef(workInProgress);
- }
}
bubbleProperties(workInProgress);
return null;
@@ -1254,10 +1233,6 @@ function completeWork(
newProps,
renderLanes,
);
-
- if (current.ref !== workInProgress.ref) {
- markRef(workInProgress);
- }
} else {
if (!newProps) {
if (workInProgress.stateNode === null) {
@@ -1310,11 +1285,6 @@ function completeWork(
markUpdate(workInProgress);
}
}
-
- if (workInProgress.ref !== null) {
- // If there is a ref on a host node we need to schedule a callback
- markRef(workInProgress);
- }
}
bubbleProperties(workInProgress);
@@ -1739,16 +1709,16 @@ function completeWork(
workInProgress.stateNode = scopeInstance;
prepareScopeUpdate(scopeInstance, workInProgress);
if (workInProgress.ref !== null) {
- markRef(workInProgress);
+ // Scope components always do work in the commit phase if there's a
+ // ref attached.
markUpdate(workInProgress);
}
} else {
if (workInProgress.ref !== null) {
+ // Scope components always do work in the commit phase if there's a
+ // ref attached.
markUpdate(workInProgress);
}
- if (current.ref !== workInProgress.ref) {
- markRef(workInProgress);
- }
}
bubbleProperties(workInProgress);
return null;
diff --git a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js
new file mode 100644
index 0000000000000..a32b826597f22
--- /dev/null
+++ b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+let React;
+let Scheduler;
+let ReactNoop;
+let act;
+let assertLog;
+
+describe('ReactFiberRefs', () => {
+ beforeEach(() => {
+ jest.resetModules();
+ React = require('react');
+ Scheduler = require('scheduler');
+ ReactNoop = require('react-noop-renderer');
+ act = require('internal-test-utils').act;
+ assertLog = require('internal-test-utils').assertLog;
+ });
+
+ test('ref is attached even if there are no other updates (class)', async () => {
+ let component;
+ class Component extends React.PureComponent {
+ render() {
+ Scheduler.log('Render');
+ component = this;
+ return 'Hi';
+ }
+ }
+
+ const ref1 = React.createRef();
+ const ref2 = React.createRef();
+ const root = ReactNoop.createRoot();
+
+ // Mount with ref1 attached
+ await act(() => root.render(