目录React.forwardRef传递泛型参数使用forwardRef暴露组建的方法和属性泛型参数react forwardRef 导致 泛型丢失实现方式如下总结
使用React函数组件开发的过程中会遇到父组件调用子组件的方法或者属性的场景,首次先说怎么通过React.forwardRef来将子组件的属性或者方法暴露给父组件
子组件
import { Box, Typography } from “@mui/material”;
import { forwardRef, useImperativeHandle } from “react”;
interface LocationChildProps {
data: string;
}
export interface LocationChildRef {
sayType(): void;
}
const LocationChild=forwardRef<LocationChildRef, LocationChildProps>((props, ref)=> {
useImperativeHandle(ref, ()=> ({
sayType() {
console.log(“子组件的data是 ” + typeof props.data);
},
}));
return (
<Box>
<Typography>{typeof props.data}</Typography>
</Box>
);
});
export default LocationChild;
import { forwardRef, useImperativeHandle } from “react”;
interface LocationChildProps {
data: string;
}
export interface LocationChildRef {
sayType(): void;
}
const LocationChild=forwardRef<LocationChildRef, LocationChildProps>((props, ref)=> {
useImperativeHandle(ref, ()=> ({
sayType() {
console.log(“子组件的data是 ” + typeof props.data);
},
}));
return (
<Box>
<Typography>{typeof props.data}</Typography>
</Box>
);
});
export default LocationChild;
在子组件中我们需要接受一个key为data的props,然后在子组件中展示这个值,并且通过useImperativeHandle向外暴露一个sayType的方法, 最后用forwardRef将子组件封装然后暴露出去,这里forwardRef的作用就是包装该组件为一个可以通过Ref访问的组件。
父组件
import { Button } from “@mui/material”;
import { useRef } from “react”;
import ConfigDetailContainer from “https://www.jb51.net/options/ConfigDetailContainer”;
import LocationChild, { LocationChildRef } from “https://www.jb51.net/article/LocationChild”;
export default function DeviceLocation() {
const locationChildRef=useRef<LocationChildRef>();
const handleClick=()=> {
locationChildRef.current.sayType()
// 输出: 子组件的type是 string
};
return (
<ConfigDetailContainer title=”device.configTabs.LOCATION_HISTORY”>
<LocationChild ref={locationChildRef} data=”asdafaf”></LocationChild>
<Button onClick={handleClick}>查看子组件的type的类型</Button>
</ConfigDetailContainer>
);
}
import { useRef } from “react”;
import ConfigDetailContainer from “https://www.jb51.net/options/ConfigDetailContainer”;
import LocationChild, { LocationChildRef } from “https://www.jb51.net/article/LocationChild”;
export default function DeviceLocation() {
const locationChildRef=useRef<LocationChildRef>();
const handleClick=()=> {
locationChildRef.current.sayType()
// 输出: 子组件的type是 string
};
return (
<ConfigDetailContainer title=”device.configTabs.LOCATION_HISTORY”>
<LocationChild ref={locationChildRef} data=”asdafaf”></LocationChild>
<Button onClick={handleClick}>查看子组件的type的类型</Button>
</ConfigDetailContainer>
);
}
父组件中需要通过useRef来创建ref并传递给子组件,这样父子组件就建立了连接,父组件可以通过ref来访问子组件中自定义暴露的属性或方法。
这里的操作就是父组件点击按钮控制台打印子组件接收到的data这个prop的类型。
现在新的问题就是我们的父组件传递的data的类型不是固定的,这时候子组件就要将data的类型用泛型来定义,所以这里就有了fowardRef传递泛型参数的问题:
我们可以这样改造子组件,思路就是将这个组件改为工厂hansh的生成模式:
import { Box, Typography } from “@mui/material”;
import { forwardRef, useImperativeHandle } from “react”;
export interface LocationChildProps<T=string> {
data: T;
}
export interface LocationChildRef {
sayType(): void;
}
const LocationChild=function <T>() {
return forwardRef<LocationChildRef, LocationChildProps<T>>((props, ref)=> {
useImperativeHandle(ref, ()=> ({
sayType() {
console.log(“子组件的data是 ” + typeof props.data);
},
}));
return (
<Box>
<Typography>{typeof props.data}</Typography>
</Box>
);
});
};
export default LocationChild;
import { forwardRef, useImperativeHandle } from “react”;
export interface LocationChildProps<T=string> {
data: T;
}
export interface LocationChildRef {
sayType(): void;
}
const LocationChild=function <T>() {
return forwardRef<LocationChildRef, LocationChildProps<T>>((props, ref)=> {
useImperativeHandle(ref, ()=> ({
sayType() {
console.log(“子组件的data是 ” + typeof props.data);
},
}));
return (
<Box>
<Typography>{typeof props.data}</Typography>
</Box>
);
});
};
export default LocationChild;
然后在父组件中使用
import { Button } from “@mui/material”;
import { PropsWithRef, useRef } from “react”;
import ConfigDetailContainer from “https://www.jb51.net/options/ConfigDetailContainer”;
import LocationChild, { LocationChildProps, LocationChildRef } from “https://www.jb51.net/article/LocationChild”;
export default function DeviceLocation() {
const locationChildRefString=useRef<LocationChildRef>();
const locationChildRefBoolean=useRef<LocationChildRef>();
const handleClick=()=> {
locationChildRefString.current.sayType();
locationChildRefBoolean.current.sayType();
};
const LocationChildComponent=LocationChild<string>();
const createComponent=function <T>(props: PropsWithRef<any>, ref: React.MutableRefObject<LocationChildRef>) {
const Mycomponent=LocationChild<T>();
return <Mycomponent ref={ref} {…props}></Mycomponent>;
};
return (
<ConfigDetailContainer title=”device.configTabs.LOCATION_HISTORY”>
<LocationChildComponent ref={locationChildRefString} data=
import { PropsWithRef, useRef } from “react”;
import ConfigDetailContainer from “https://www.jb51.net/options/ConfigDetailContainer”;
import LocationChild, { LocationChildProps, LocationChildRef } from “https://www.jb51.net/article/LocationChild”;
export default function DeviceLocation() {
const locationChildRefString=useRef<LocationChildRef>();
const locationChildRefBoolean=useRef<LocationChildRef>();
const handleClick=()=> {
locationChildRefString.current.sayType();
locationChildRefBoolean.current.sayType();
};
const LocationChildComponent=LocationChild<string>();
const createComponent=function <T>(props: PropsWithRef<any>, ref: React.MutableRefObject<LocationChildRef>) {
const Mycomponent=LocationChild<T>();
return <Mycomponent ref={ref} {…props}></Mycomponent>;
};
return (
<ConfigDetailContainer title=”device.configTabs.LOCATION_HISTORY”>
<LocationChildComponent ref={locationChildRefString} data=
我们可以直接调用LocationChild方法生成组件,也可以再度封装为createComponent这样的方法,这样就实现了forwardRef中使用泛型参数的需求。
网上没有找到合适的方案,看了 antd 的源码
const ForwardTable=React.forwardRef(InternalTable) as <RecordType extends object=any>(
? props: React.PropsWithChildren<TableProps<RecordType>> & { ref?: React.Ref<HTMLDivElement> },
)=> React.ReactElement;
// so u can use
<Table<{id: string, b: number}> ?/>
? props: React.PropsWithChildren<TableProps<RecordType>> & { ref?: React.Ref<HTMLDivElement> },
)=> React.ReactElement;
// so u can use
<Table<{id: string, b: number}> ?/>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:react中的useImperativeHandle()和forwardRef()用法React将组件作为参数进行传递的3种方法实例react navigation中点击底部tab怎么传递参数
© 版权声明
文章版权归作者所有,未经允许请勿转载。