摘要
在类组件中,父组件获取子组件实例是通过ref实现的,比如以下代码
import React, { Component } from "react";
import Son from "./son";
export default class Parent extends Component {
sonRef = React.createRef();
fatherSetCount = () => {
this.sonRef.current.setCount();
};
render() {
return (
<div>
<Son ref={this.sonRef} />
<br />
<button onClick={() => this.sonRef.current.setCount()}>
fatherSetCount
</button>
</div>
);
}
}
import React, { Component } from "react";
export default class Son extends Component {
state = {
count: 0,
};
setCount = () => {
this.setState({
count: ++this.state.count,
});
};
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.setCount}>setCount</button>
</div>
);
}
}
那么在函数组件中如何获取子组件实例呢,在介绍方法之前首先介绍几个api
useRef
useRef返回一个可变的 ref 对象,其.current属性被初始化为传入的参数(initialValue)useRef返回的 ref 对象在组件的整个生命周期内持续存在- ref对象地址从头到尾都不会改变
- useRef变化不会主动使页面渲染
forwardRef
我们在函数组件里直接写ref时,控制台会报警告
从上图知道,函数组件要使用ref属性,需要使用forwardRef,转发ref,比如以下代码,父组件传递子组件ref属性,子组件通过forwardRef接受并传递给input,在父组件中通过sonRef.current.value即可获取input的值
import React, { useRef } from 'react'
import Son from "./son";
export default function Parent() {
const sonRef = useRef();
const logInput = () => {
console.log(sonRef.current.value);
}
return (
<div>
<Son ref={sonRef}/>
<button onClick={logInput}>logInput</button>
</div>
)
}
import React, { forwardRef } from 'react'
const SonComponent = forwardRef((props,ref) => {
return (
<div>
<input type="text" ref={ref} />
</div>
)
})
export default SonComponent;
那么问题来了,就算这样父组件还是拿不到子组件的方法,这时候就需要搭配useImperativeHandle来实现
useImperativeHandle
useImperativeHandle可以让你在使用ref时自定义暴露给父组件的实例值,简单来说就是可以选择将啥暴露给父组件,而不是像类组件中使用ref那样全部暴露,所以,useImperativeHandle用来减少暴露给父组件获取的DOM元素属性, 只暴露给父组件需要用到的DOM方法
参数:
- 参数1: 父组件传递的ref属性
- 参数2: 返回一个对象, 以供给父组件中通过ref.current调用该对象中的方法
🌰:函数组件父组件调用子组件函数实例
import React from "react";
import Child from "./Child";
import { useRef } from "react";
export default function Demo() {
const textInput = useRef(null);
const childRef = useRef(null);
function onButtonClick() {
textInput.current.focus();
}
function childClick() {
console.log(childRef.current)
childRef.current.childFun();
}
return (
<div>
<input type="text" ref={textInput} />
<button onClick={onButtonClick}>Focus the input</button>
<Child ref={childRef}/>
<button onClick={childClick}>childClick</button>
</div>
);
}
import React from "react";
import { forwardRef, useImperativeHandle } from "react";
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
childFun,
}));
const childFun = () => {
console.log("999");
};
return <div>Child</div>;
});
export default Child;