Skip to content

Commit 3513824

Browse files
committed
Convert string ref props to callback props (#28398)
When enableRefAsProp is on, we should always use the props as the source of truth for refs. Not a field on the fiber. In the case of string refs, this presents a problem, because string refs are not passed around internally as strings; they are converted to callback refs. The ref used by the reconciler is not the same as the one the user provided. But since this is a deprecated feature anyway, what we can do is clone the props object and replace it with the internal callback ref. Then we can continue to use the props object as the source of truth. This means the internal callback ref will leak into userspace. The receiving component will receive a callback ref even though the parent passed a string. Which is weird, but again, this is a deprecated feature, and we're only leaving it around behind a flag so that Meta can keep using string refs temporarily while they finish migrating their codebase. DiffTrain build for commit dc30644.
1 parent bb2b69a commit 3513824

File tree

13 files changed

+706
-703
lines changed

13 files changed

+706
-703
lines changed

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js

+120-109
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<1d3d484449a45d9d48c574d191f78a9b>>
10+
* @generated SignedSource<<c84520e2b9d33ee51d806026be234a8a>>
1111
*/
1212

1313
"use strict";
@@ -5039,127 +5039,138 @@ if (__DEV__) {
50395039
return trackUsedThenable(thenableState$1, thenable, index);
50405040
}
50415041

5042-
function coerceRef(returnFiber, current, element) {
5043-
var mixedRef;
5044-
5045-
{
5046-
// Old behavior.
5047-
mixedRef = element.ref;
5048-
}
5049-
5050-
if (
5051-
mixedRef !== null &&
5052-
typeof mixedRef !== "function" &&
5053-
typeof mixedRef !== "object"
5054-
) {
5055-
{
5056-
if (
5057-
// Will already throw with "Function components cannot have string refs"
5058-
!(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs"
5059-
!(
5060-
typeof element.type === "function" && !isReactClass(element.type)
5061-
) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set"
5062-
element._owner
5063-
) {
5064-
var componentName =
5065-
getComponentNameFromFiber(returnFiber) || "Component";
5066-
5067-
if (!didWarnAboutStringRefs[componentName]) {
5068-
error(
5069-
'Component "%s" contains the string ref "%s". Support for string refs ' +
5070-
"will be removed in a future major release. We recommend using " +
5071-
"useRef() or createRef() instead. " +
5072-
"Learn more about using refs safely here: " +
5073-
"https://reactjs.org/link/strict-mode-string-ref",
5074-
componentName,
5075-
mixedRef
5076-
);
5042+
function convertStringRefToCallbackRef(
5043+
returnFiber,
5044+
current,
5045+
element,
5046+
mixedRef
5047+
) {
5048+
var owner = element._owner;
50775049

5078-
didWarnAboutStringRefs[componentName] = true;
5079-
}
5080-
}
5050+
if (!owner) {
5051+
if (typeof mixedRef !== "string") {
5052+
throw new Error(
5053+
"Expected ref to be a function, a string, an object returned by React.createRef(), or null."
5054+
);
50815055
}
50825056

5083-
if (element._owner) {
5084-
var owner = element._owner;
5085-
var inst;
5057+
throw new Error(
5058+
"Element ref was specified as a string (" +
5059+
mixedRef +
5060+
") but no owner was set. This could happen for one of" +
5061+
" the following reasons:\n" +
5062+
"1. You may be adding a ref to a function component\n" +
5063+
"2. You may be adding a ref to a component that was not created inside a component's render method\n" +
5064+
"3. You have multiple copies of React loaded\n" +
5065+
"See https://reactjs.org/link/refs-must-have-owner for more information."
5066+
);
5067+
}
50865068

5087-
if (owner) {
5088-
var ownerFiber = owner;
5069+
if (owner.tag !== ClassComponent) {
5070+
throw new Error(
5071+
"Function components cannot have string refs. " +
5072+
"We recommend using useRef() instead. " +
5073+
"Learn more about using refs safely here: " +
5074+
"https://reactjs.org/link/strict-mode-string-ref"
5075+
);
5076+
} // At this point, we know the ref isn't an object or function but it could
5077+
// be a number. Coerce it to a string.
50895078

5090-
if (ownerFiber.tag !== ClassComponent) {
5091-
throw new Error(
5092-
"Function components cannot have string refs. " +
5093-
"We recommend using useRef() instead. " +
5094-
"Learn more about using refs safely here: " +
5095-
"https://reactjs.org/link/strict-mode-string-ref"
5096-
);
5097-
}
5079+
{
5080+
checkPropStringCoercion(mixedRef, "ref");
5081+
}
50985082

5099-
inst = ownerFiber.stateNode;
5100-
}
5083+
var stringRef = "" + mixedRef;
51015084

5102-
if (!inst) {
5103-
throw new Error(
5104-
"Missing owner for string ref " +
5105-
mixedRef +
5106-
". This error is likely caused by a " +
5107-
"bug in React. Please file an issue."
5108-
);
5109-
} // Assigning this to a const so Flow knows it won't change in the closure
5085+
{
5086+
if (
5087+
// Will already warn with "Function components cannot be given refs"
5088+
!(typeof element.type === "function" && !isReactClass(element.type))
5089+
) {
5090+
var componentName =
5091+
getComponentNameFromFiber(returnFiber) || "Component";
51105092

5111-
var resolvedInst = inst;
5093+
if (!didWarnAboutStringRefs[componentName]) {
5094+
error(
5095+
'Component "%s" contains the string ref "%s". Support for string refs ' +
5096+
"will be removed in a future major release. We recommend using " +
5097+
"useRef() or createRef() instead. " +
5098+
"Learn more about using refs safely here: " +
5099+
"https://reactjs.org/link/strict-mode-string-ref",
5100+
componentName,
5101+
stringRef
5102+
);
51125103

5113-
{
5114-
checkPropStringCoercion(mixedRef, "ref");
5104+
didWarnAboutStringRefs[componentName] = true;
51155105
}
5106+
}
5107+
}
51165108

5117-
var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref
5109+
var inst = owner.stateNode;
51185110

5119-
if (
5120-
current !== null &&
5121-
current.ref !== null &&
5122-
typeof current.ref === "function" &&
5123-
current.ref._stringRef === stringRef
5124-
) {
5125-
return current.ref;
5126-
}
5111+
if (!inst) {
5112+
throw new Error(
5113+
"Missing owner for string ref " +
5114+
stringRef +
5115+
". This error is likely caused by a " +
5116+
"bug in React. Please file an issue."
5117+
);
5118+
} // Check if previous string ref matches new string ref
51275119

5128-
var ref = function (value) {
5129-
var refs = resolvedInst.refs;
5120+
if (
5121+
current !== null &&
5122+
current.ref !== null &&
5123+
typeof current.ref === "function" &&
5124+
current.ref._stringRef === stringRef
5125+
) {
5126+
// Reuse the existing string ref
5127+
var currentRef = current.ref;
5128+
return currentRef;
5129+
} // Create a new string ref
51305130

5131-
if (value === null) {
5132-
delete refs[stringRef];
5133-
} else {
5134-
refs[stringRef] = value;
5135-
}
5136-
};
5131+
var ref = function (value) {
5132+
var refs = inst.refs;
51375133

5138-
ref._stringRef = stringRef;
5139-
return ref;
5134+
if (value === null) {
5135+
delete refs[stringRef];
51405136
} else {
5141-
if (typeof mixedRef !== "string") {
5142-
throw new Error(
5143-
"Expected ref to be a function, a string, an object returned by React.createRef(), or null."
5144-
);
5145-
}
5146-
5147-
if (!element._owner) {
5148-
throw new Error(
5149-
"Element ref was specified as a string (" +
5150-
mixedRef +
5151-
") but no owner was set. This could happen for one of" +
5152-
" the following reasons:\n" +
5153-
"1. You may be adding a ref to a function component\n" +
5154-
"2. You may be adding a ref to a component that was not created inside a component's render method\n" +
5155-
"3. You have multiple copies of React loaded\n" +
5156-
"See https://reactjs.org/link/refs-must-have-owner for more information."
5157-
);
5158-
}
5137+
refs[stringRef] = value;
51595138
}
5139+
};
5140+
5141+
ref._stringRef = stringRef;
5142+
return ref;
5143+
}
5144+
5145+
function coerceRef(returnFiber, current, workInProgress, element) {
5146+
var mixedRef;
5147+
5148+
{
5149+
// Old behavior.
5150+
mixedRef = element.ref;
51605151
}
51615152

5162-
return mixedRef;
5153+
var coercedRef;
5154+
5155+
if (
5156+
mixedRef !== null &&
5157+
typeof mixedRef !== "function" &&
5158+
typeof mixedRef !== "object"
5159+
) {
5160+
// Assume this is a string ref. If it's not, then this will throw an error
5161+
// to the user.
5162+
coercedRef = convertStringRefToCallbackRef(
5163+
returnFiber,
5164+
current,
5165+
element,
5166+
mixedRef
5167+
);
5168+
} else {
5169+
coercedRef = mixedRef;
5170+
} // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We
5171+
// should always read the ref from the prop.
5172+
5173+
workInProgress.ref = coercedRef;
51635174
}
51645175

51655176
function throwOnInvalidObjectType(returnFiber, newChild) {
@@ -5415,7 +5426,7 @@ if (__DEV__) {
54155426
) {
54165427
// Move based on index
54175428
var existing = useFiber(current, element.props);
5418-
existing.ref = coerceRef(returnFiber, current, element);
5429+
coerceRef(returnFiber, current, existing, element);
54195430
existing.return = returnFiber;
54205431

54215432
{
@@ -5428,7 +5439,7 @@ if (__DEV__) {
54285439
} // Insert
54295440

54305441
var created = createFiberFromElement(element, returnFiber.mode, lanes);
5431-
created.ref = coerceRef(returnFiber, current, element);
5442+
coerceRef(returnFiber, current, created, element);
54325443
created.return = returnFiber;
54335444

54345445
{
@@ -5534,7 +5545,7 @@ if (__DEV__) {
55345545
lanes
55355546
);
55365547

5537-
_created.ref = coerceRef(returnFiber, null, newChild);
5548+
coerceRef(returnFiber, null, _created, newChild);
55385549
_created.return = returnFiber;
55395550

55405551
{
@@ -6397,7 +6408,7 @@ if (__DEV__) {
63976408

63986409
var _existing = useFiber(child, element.props);
63996410

6400-
_existing.ref = coerceRef(returnFiber, child, element);
6411+
coerceRef(returnFiber, child, _existing, element);
64016412
_existing.return = returnFiber;
64026413

64036414
{
@@ -6439,7 +6450,7 @@ if (__DEV__) {
64396450
lanes
64406451
);
64416452

6442-
_created4.ref = coerceRef(returnFiber, currentFirstChild, element);
6453+
coerceRef(returnFiber, currentFirstChild, _created4, element);
64436454
_created4.return = returnFiber;
64446455

64456456
{
@@ -25696,7 +25707,7 @@ if (__DEV__) {
2569625707
return root;
2569725708
}
2569825709

25699-
var ReactVersion = "18.3.0-canary-ddd736d25-20240221";
25710+
var ReactVersion = "18.3.0-canary-dc30644ca-20240221";
2570025711

2570125712
// Might add PROFILE later.
2570225713

0 commit comments

Comments
 (0)