场景:需要在函数组件外部调用函数组件ref对象的方法或者操作ref,通过下面的实战代码,在antd upload组件外部触发upload组件打开文件上传弹窗
函数式组件
// uploader.tsx
import React, {
forwardRef,
useRef,
useImperativeHandle,
} from 'react';
import { Upload } from 'antd';
function Uploader(
props: IProps,
ref:
| ((instance: unknown) => void)
| React.RefObject<unknown>
| null
| undefined,
) {
const uploadRef = useRef<HTMLAnchorElement>(null);
useImperativeHandle(
ref,
() => ({
doUpload() {
if (uploadRef.current) {
uploadRef.current.click();
}
},
}),
[],
);
return (
<span className={style}>
<Upload
className="upload-list-inline"
...
>
<a ref={uploadRef}>
{props.showHandler && (
<Button type="dashed" size="small">
+ 上传附件
</Button>
)}
</a>
{!props.showHandler && props.fileList?.length === 0 && '暂无数据'}
</Upload>
</span>
);
}
export default forwardRef(Uploader);
通过上面的函数式组件代码,我们调用了其他组件ref上的方法,并且定义了一个doUpload方法暴露给外面调用
class组件对外暴露方法
// ClassCustomer.tsx
import React, { PureComponent } from 'react';
class ClassCustomer extends PureComponent<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state={
todo:false,
}
}
//向外层提供ref实例
componentDidMount() {
this.props.onRef(this);
}
changState = () => {
this.setState({todo:true})
}
render(){
return
<>
...
</>
}
}
export default ClassCustomer;
如何使用ref上的方法
介绍一下在函数式组件和class组件中如何调用doUpload方法
-
函数式组件调用函数式组件中的方法
// FCCustomer.tsx import React, { useRef, forwardRef, useImperativeHandle } from 'react'; import Uploader from './uploader'; const FCCustomer = ( props: IProps, ref: | React.RefObject | ((instance: unknown) => void) | null | undefined, ) => { const childRef = useRef(null); // 继续把函数式组件ref上的方法向外暴露 useImperativeHandle( ref, () => ({ doUpload() { if (childRef.current) { childRef.current.doUpload(); } }, }), [], ); return ( <Collapse defaultActiveKey={['attachment']} ... > <Panel header="附件" key="attachment" extra={ <Button type="dashed" size="small" onClick={(e) => { e.stopPropagation(); if (childRef.current) { childRef.current.doUpload(); } }} > + 添加 } > <Uploader showHandler={false} ref={childRef} ... /> ); };
export default forwardRef(FCCustomer);
-
class组件调用 函数式组件的ref 和class组件的Ref
// Costumer.tsx
import React, { Component,createRef } from 'react'; import FCCustomer from './FCCustomer' import ClassCustomer from './ClassCustomer'
class Costumer extends Component<IProps, IState> { FCCustomerChild: React.RefObject; ClassCustomerChild: any; constructor(props: IProps) { super(props); // 可以调用ref上对外暴露的指定方法 this.FCCustomerChild = React.createRef(); }
onRef = (ref: any) => { this.ClassCustomerChild = ref; };
// 可以调用class ref上的方法 doRefFc = () => { this.ClassCustomerChild.showEdit(id, comment); };
render(){ return <> <Icon type="paper-clip" onClick={() => { if (this.FCCustomerChild && this.FCCustomerChild.current) { this.FCCustomerChild.current.doUpload(); } }} /> <FCCustomer ref={this.attachmentChild} ... /> </> } }