function coerceRef(returnFiber, current, element) {
// 获取 ref
var mixedRef = element.ref;
// 如果 ref 是字符串且严格模式下或者有关于字符串 ref 的警告,则进行一些额外的检查
if (
mixedRef !== null &&
typeof mixedRef !== 'function' &&
typeof mixedRef !== 'object'
) {
{
// 在开发环境下,如果是字符串 ref,并且在严格模式下或者开启了字符串 ref 警告,则发出警告
if (
(returnFiber.mode & StrictLegacyMode || warnAboutStringRefs) &&
// 如果 owner 和 self 相等,说明这是一个函数组件
!(element._owner && element._self && element._owner.stateNode !== element._self)
) {
var componentName = getComponentNameFromFiber(returnFiber) || 'Component';
// 发出警告
if (!didWarnAboutStringRefs[componentName]) {
{
error(
'A string ref, "%s", has been found within a strict mode tree. ' +
'String refs are a source of potential bugs and should be avoided. ' +
'We recommend using useRef() or createRef() instead. ' +
'Learn more about using refs safely here: ' +
'https://reactjs.org/link/strict-mode-string-ref',
mixedRef
);
}
didWarnAboutStringRefs[componentName] = true;
}
}
}
// 如果有 owner,则进行一些额外的检查
if (element._owner) {
var owner = element._owner;
var inst;
if (owner) {
var ownerFiber = owner;
// 如果 owner 不是 ClassComponent,则抛出错误,因为函数组件不能有字符串 ref
if (ownerFiber.tag !== ClassComponent) {
throw new Error(
'Function components cannot have string refs. ' +
'We recommend using useRef() instead. ' +
'Learn more about using refs safely here: ' +
'https://reactjs.org/link/strict-mode-string-ref'
);
}
inst = ownerFiber.stateNode;
}
if (!inst) {
throw new Error(
"Missing owner for string ref " + mixedRef + ". This error is likely caused by a " +
'bug in React. Please file an issue.'
);
}
// 将 ref 转换成函数形式
var resolvedInst = inst;
{
// 在开发环境下,检查字符串 ref 的强制转换
checkPropStringCoercion(mixedRef, 'ref');
}
var stringRef = '' + mixedRef;
// 如果当前的字符串 ref 和之前的字符串 ref 一样,直接返回之前的 ref
if (
current !== null &&
current.ref !== null &&
typeof current.ref === 'function' &&
current.ref._stringRef === stringRef
) {
return current.ref;
}
// 创建一个新的 ref
var ref = function (value) {
var refs = resolvedInst.refs;
if (refs === emptyRefsObject) {
refs = resolvedInst.refs = {};
}
if (value === null) {
delete refs[stringRef];
} else {
refs[stringRef] = value;
}
};
ref._stringRef = stringRef;
return ref;
} else {
// 如果没有 owner,但 ref 不是字符串,则抛出错误
if (typeof mixedRef !== 'string') {
throw new Error('Expected ref to be a function, a string, an object returned by React.createRef(), or null.');
}
// 如果没有 owner,但 ref 是字符串,则抛出错误,说明可能是以下几种情况之一
throw new Error(
"Element ref was specified as a string (" + mixedRef + ") but no owner was set. This could happen for one of" +
' the following reasons:\n' +
'1. You may be adding a ref to a function component\n' +
"2. You may be adding a ref to a component that was not created inside a component's render method\n" +
'3. You have multiple copies of React loaded\n' +
'See https://reactjs.org/link/refs-must-have-owner for more information.'
);
}
}
// 如果不满足条件,直接返回 ref
return mixedRef;
}
mixedRef 是字符串并且在严格模式或者开启了字符串 ref 警告时的处理:
const element = <div ref="myStringRef" />;
const returnFiber = /* some return fiber */;
const current = /* some current fiber */;
coerceRef(returnFiber, current, element);
// 输出警告,因为字符串 ref 在严格模式或者开启了字符串 ref 警告时会发出警告
element 有 owner 并且 owner 是 ClassComponent 时的处理
class MyComponent extends React.Component {
render() {
return <div ref="myStringRef" />;
}
}
const myComponentInstance = new MyComponent();
const element = myComponentInstance.render();
const returnFiber = /* some return fiber */;
const current = /* some current fiber */;
coerceRef(returnFiber, current, element);
// 将字符串 ref 转换为函数 ref,并且在 owner 不是 ClassComponent 时抛出错误
-
element有 owner 但是 owner 不是 ClassComponent 时的处理:const element = <div ref="myStringRef" />; const returnFiber = /* some return fiber */; const current = /* some current fiber */; coerceRef(returnFiber, current, element); // 输出错误,因为函数组件不能有字符串 ref -
element没有 owner 且mixedRef不是字符串时的处理:const element = <div ref={() => {}} />; const returnFiber = /* some return fiber */; const current = /* some current fiber */; coerceRef(returnFiber, current, element); // 不会输出警告或错误,直接返回 ref -
element有 owner 但是 owner 不是 ClassComponent 时的处理:
const element = <div ref="myStringRef" />;
const returnFiber = /* some return fiber */;
const current = /* some current fiber */;
coerceRef(returnFiber, current, element);
// 输出错误,因为函数组件不能有字符串 ref
element没有 owner 且mixedRef不是字符串时的处理:
const element = <div ref={() => {}} />;
const returnFiber = /* some return fiber */;
const current = /* some current fiber */;
coerceRef(returnFiber, current, element);
// 不会输出警告或错误,直接返回 ref
element没有 owner 且mixedRef是字符串时的处理:
const element = <div ref="myStringRef" />;
const returnFiber = /* some return fiber */;
const current = /* some current fiber */;
coerceRef(returnFiber, current, element);
// 输出错误,因为没有 owner,但是字符串 ref 会要求有 owner