转载声明:本文引用自【react中父组件调用子组件的方法】,如有侵权,请联系删除
常用实现方式
方式一:类组件中的使用React.createRef()
- 优点:
- 写法简单易懂
- 缺点:
- 假如子组件是嵌套了HOC,就无法指向真实子组件
import React , { Component } from "react"
// ---------- 子组件 ----------
class Child extends Component<any, any> {
func(){
console.log("执行我")
}
render(){
return (<div>子组件</div>);
}
}
// ---------- 父组件 ----------
class Parent extends Component<any, any> {
ChildRef = React.createRef<any>();
constructor(props) {
super(props);
}
handleOnClick(){
this.ChildRef?.current?.func?.();
}
render(){
return (<div>
<button onClick={this.handleOnClick}>click</button>
<Child ref={this.ChildRef} />
</div>);
}
}
方式二:使用ref回调函数的方式
此方式跟方式一基本相同, 只是创建和设置Ref的方式不同而已
- 优点:
- 写法更简单易懂
- 没有多余的代码
- 缺点:
- 假如子组件是嵌套了HOC,就无法指向真实子组件
import React , { Component } from "react"
// ---------- 子组件 ----------
class Child extends Component<any, any> {
func(){
console.log("执行我")
}
render(){
return (<div>子组件</div>);
}
}
// ---------- 父组件 ----------
class Parent extends Component<any, any> {
ChildRef: any = null
handleOnClick(){
this.ChildRef?.func?.();
}
render(){
return (<div>
<button onClick={this.handleOnClick}>click</button>
<Child ref={ node => this.ChildRef = node }/>
</div>);
}
}
方式三:使用props自定义属性传递函数
- 优点:
- 写法简单易懂
- 假如子组件是嵌套了HOC,也可以指向真实子组件
- 缺点:
- 需要自定义props属性
import React , { Component } from "react"
// ---------- 子组件 ----------
type ChildProps = {
onRef?: (node: any) => void;
}
class Child extends Component<ChildProps, any> {
componentDidMount(){
this.props?.onRef?.(this);
}
func(){
console.log("执行我")
}
render(){
return (<div>子组件</div>);
}
}
// ---------- 父组件 ----------
class Parent extends Component<any, any> {
ChildRef: any = null
handleOnClick(){
this.Child?.func?.();
}
render(){
return (<div>
<button onClick={this.handleOnClick}>click</button>
<Child onRef={ node => this.ChildRef = node } />
</div>);
}
}
方式四:函数式和hooks写法
其实下面的缺点基本不算缺点了,因为函数式写法,下面算是简单的了。使用forwardRef只会让你的组件定义的更复杂
- 优点:
- 写法简单易懂
- 假如子组件嵌套了HOC,也可以指向真实子组件
- 缺点:
- 需要自定义props属性
- 需要自定义暴露的方法
import React, { useImperativeHandle } from 'react';
// ---------- 子组件 ----------
type ChildProps = {
onRef?: any;
}
const Child: React.FC<ChildProps> = props => {
//用useImperativeHandle暴露一些外部ref能访问的属性
useImperativeHandle(props.onRef, () => {
return {
func: func,
};
});
const func = () => {
console.log('执行我');
}
return <div>子组件</div>;
};
// ---------- 父组件 ----------
const Parent: React.FC = () => {
// 以下两种写法均正确
// const ChildRef = React.createRef();
const ChildRef: any = useRef();
function handleOnClick() {
ChildRef.current?.func?.();
}
return (
<div>
<button onClick={handleOnClick}>click</button>
<Child onRef={ChildRef} />
</div>
);
};
方式五:使用forwardRef结合高阶组件转发子组件的ref
import React from 'react';
// ---------- 子组件 ----------
// 自定义可以抛出子组件ref的HOC
const withChild: (Comp: any) => any = Comp => {
return React.forwardRef((props, ref) => {
return <Comp ref={ref} {...props} />;
});
}
class Child extends Component {
func = () => {
console.log('打印了我');
};
render() {
return <div>我是个测试的子组件</div>;
}
}
const ChildWrapper = withChild(Child);
// ---------- 父组件 ----------
const Parent = () => {
// 以下两种写法均正确
// const ChildRef = React.createRef();
const ChildRef: any = useRef();
function handleOnClick() {
ChildRef.current?.func?.();
}
return (
<div>
<button onClick={handleOnClick}>click</button>
<Child ref={ChildRef} />
</div>
);
};
方式六:使用forwardRef结合装饰器转发子组件的ref
import React, { Component } from 'react';
// ---------- 子组件 ----------
// 自定义可以抛出子组件ref的HOC
const Log: (Comp: any) => any = Comp => {
const Wrapper = (props: any) => {
const {forwardRef, ...rest} = props;
return <Comp ref={forwardRef} {...rest} />;
};
return React.forwardRef((props, ref) => {
return <Wrapper {...props} forwardRef={ref} />;
});
}
@Log
class Child extends Component<any, any> {
function func() {
console.log('打印了我');
};
render() {
return <div>我是个测试的子组件</div>;
}
}
// ---------- 父组件 ----------
const Parent = () => {
// 以下两种写法均正确
// const ChildRef = React.createRef();
const ChildRef: any = useRef();
function handleOnClick() {
ChildRef.current?.func?.();
}
return (
<div>
<button onClick={handleOnClick}>click</button>
<Child ref={ChildRef} />
</div>
);
};
总结
- 父组件调子组件函数有两种情况
- 子组件无HOC嵌套
- 有HOC嵌套
选择什么方法,具体情况具体分析。使用onRef自定义props的方式更实用,无论组件是否需要嵌套HOC,嵌套多少层,一把梭就行了,不用改组件里边的代码。一个写好的组件,只需要做加法就好了