ref和refs这两个属性时间久了会弄混淆,都是用来获取dom元素实例的相关的,直接上代码。
ref的值为函数时
testClick = () => {
console.info(this.input); // 打印input的dom实例
}
render() {
<>
<input type="text" ref={c => this.input = c;} onClick={this.testClick} />
</>
}
ref值为具体值时
testClick = () => {
console.info(this.refs.input); // 答应input的dom实例
}
render() {
<>
<input type="text" ref="this.input" onClick={this.testClick} />
</>
}
不知道小伙伴们看出来区别没?ref属性是react支持的一个特殊的属性,可以将ref属性加载任何通过render()返回的组件中,也就是对render返回的组件进行标记,方便我们定位这个实例后的组件,方便我们突破虚拟dom的限制。 ref的值可以是一个函数,或者是一个名字。当ref的值是一个函数时,可以通过this.input直接得到dom实例,即为代码段一;当ref的值是一个值时,可以通过this.refs.input获取到dom实例。(注:只有class组件才有ref属性)
如果子组件被高阶组件多层包裹后,父组件无法通过ref的想要的dom节点。例如下面这种情况:
class Parent extends React.Component {
testClick = () => {
console.info(this.child);
}
render() {
<>
<a conClick={this.testClick}>获取Child子组件</a>
<Child ref={c => this.child = c } />
</>
}
}
class Child extends React.Component {
render() {
<>
<input type="text" ref={c => this.input = c } />
</>
}
}
export default connect(({childState}) => ({ name: childState.name }))(Form.create()(Child))
可以看到子组件Child经过connect和Form两个高级组件包裹后,ref这个时候就不是我们想要得到的结果,此时可以通过如下方法处理,无论被包裹多少层都可以获取到想要的ref。
class Parent extends React.Component {
testClick = () => {
console.info(this.childRefDom);
}
render() {
<>
<a conClick={this.testClick}>获取Child子组件</a>
<Child getInstance={(childRef) => this.childRefDom = childRef } />
</>
}
}
class Child extends React.Component {
constructor(props) {
super(props);
const { getInstance } = this.props;
getInstance && typeof getInstance === 'function' && getInstance(this);
}
render() {
<>
<input type="text" ref={c => this.input = c } />
</>
}
}
export default connect(({childState}) => ({ name: childState.name }))(Form.create()(Child))
不知道小伙伴们看明白了?父组件传递给子组件的有个getInstance函数,函数内容即使将子组件的this赋值给父组件的getRefDom这个变量。当然还有一些其他的方法,比如说react的createRef()和forwardRef等方式,都可以了解下,不过我愿称之此方法为最强。。。。