document.querySelector
之类的选择器来获取这个 dom 节点1 ) 演示代码
import React from 'react'
export default class RefDemo extends React.Component {
constructor() {
super()
this.objRef = React.createRef()
}
componentDidMount() {
setTimeout(() => {
this.refs.stringRef.textContent = 'string ref'
this.methodRef.textContent = 'method ref'
this.objRef.current.textContent = 'obj ref'
}, 1000)
}
render() {
return (
<>
<p ref="stringRef">xxxx</p>
<p ref={ele => (this.methodRef = ele)}>yyyy</p>
<p ref={this.objRef}>zzzz</p>
</>
)
}
}
2 )代码说明
stringRef
this.refs
这个对象上面挂载这个string对应的一个keyforwardRef
,后续来说function
methodRef
, 基于其 textContent
属性来重新赋值React.createRef
这个API
this.objRef = React.createRef()
去创建了一个对象
{ current: null}
, 默认值是 null
current
这个属性上面this.objRef.current
操作它就可以了createRef
3 )源码探究
从入口文件 React.js 中可见
import {createRef} from './ReactCreateRef';
定位到 ReactCreateRef.js 中
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @flow
*/
import type {RefObject} from 'shared/ReactTypes';
// an immutable object with a single mutable value
export function createRef(): RefObject {
const refObject = {
current: null,
};
if (__DEV__) {
Object.seal(refObject);
}
return refObject;
}
这个代码看上去,非常简单,它返回的就是一个简单的对象
DEV 相关的判断不是核心,忽略即可
它里面的属性 current, 默认值是 null
1 )示例演示
关于 forward ref, 先看一个示例
import React from 'react'
const TargetComponent = React.forwardRef((props, ref) => (
<input type="text" ref={ref} />
))
export default class Comp extends React.Component {
constructor() {
super()
this.ref = React.createRef()
}
componentDidMount() {
this.ref.current.value = 'ref input'
}
render() {
return <TargetComponent ref={this.ref} />
}
}
Comp
, TargetComponent
React.forwardRef
,如上代码所示
React.forwardRef
实现的 function Component2 )源码分析
定位到 forwardRef.js 中
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {REACT_FORWARD_REF_TYPE} from 'shared/ReactSymbols';
import warningWithoutStack from 'shared/warningWithoutStack';
export default function forwardRef<Props, ElementType: React$ElementType>(
render: (props: Props, ref: React$Ref<ElementType>) => React$Node,
) {
if (__DEV__) {
if (typeof render !== 'function') {
warningWithoutStack(
false,
'forwardRef requires a render function but was given %s.',
render === null ? 'null' : typeof render,
);
} else {
warningWithoutStack(
// Do not warn for 0 arguments because it could be due to usage of the 'arguments' object
render.length === 0 || render.length === 2,
'forwardRef render functions accept exactly two parameters: props and ref. %s',
render.length === 1
? 'Did you forget to use the ref parameter?'
: 'Any additional parameter will be undefined.',
);
}
if (render != null) {
warningWithoutStack(
render.defaultProps == null && render.propTypes == null,
'forwardRef render functions do not support propTypes or defaultProps. ' +
'Did you accidentally pass a React component?',
);
}
}
return {
$$typeof: REACT_FORWARD_REF_TYPE,
render,
};
}
忽略 DEV 判断代码,其本质上就只有一个 return 对象
return {
$$typeof: REACT_FORWARD_REF_TYPE,
render,
};
$$typeoff
,是 REACT_FORWARD_REF_TYPE
TargetComponent
组件最终会被创建成一个 ReactElement,比如,别名叫 ATargetComponent
组件 就是 forwordRef 返回的对象,这个不难理解,因为代码如此TargetComponent
对应的 组件A 的 type 是 TargetComponent
TargetComponent
对应的 组件A的 $$typeof
是 REACT_ELEMENT_TYPE
$$typeof
不是 REACT_FORWARD_REF_TYPE
$$typeof
都是 REACT_ELEMENT_TYPE
TargetComponent
组件最终会被React.createElement创建出来render