Reactjs 如何将TypeScript泛型与React渲染道具一起使用
我正在尝试使用泛型键入React组件的属性。问题是,当我试图通过另一个组件将该组件渲染为渲染道具时,它似乎不再能够“推断”正确的类型-相反,它默认为未知,我必须使用“as any”使其正常工作 我在这里列出了一个工作示例。请注意注释和“如有”: 代码如下:Reactjs 如何将TypeScript泛型与React渲染道具一起使用,reactjs,typescript,typescript-generics,react-typescript,Reactjs,Typescript,Typescript Generics,React Typescript,我正在尝试使用泛型键入React组件的属性。问题是,当我试图通过另一个组件将该组件渲染为渲染道具时,它似乎不再能够“推断”正确的类型-相反,它默认为未知,我必须使用“as any”使其正常工作 我在这里列出了一个工作示例。请注意注释和“如有”: 代码如下: type TabProps<T> = { data?: T; }; type TabsProps<T> = { children: ({ childrenArr }: { children
type TabProps<T> = {
data?: T;
};
type TabsProps<T> = {
children: ({
childrenArr
}: {
childrenArr: React.ReactElement<TabProps<T>>[];
}) => React.ReactElement<TabProps<T>>[];
items: React.ReactElement<TabProps<T>>[];
};
type Data = { hello: string };
const Tab = <T extends unknown>({ data }: TabProps<T>) => <div>...</div>;
const Tabs = <T extends unknown>({ children, items }: TabsProps<T>) => {
const childrenArr = useMemo(() => (Array.isArray(items) ? items : [items]), [
items
]);
// ...
// In real application this is where manipulation of the elements in the childrenArr would take place
// Since this is just an example I'll just do this
const manipulatedchildrenArr = childrenArr.map(child => {
return {
...(child as any),
props: { data: { hello: "world is manipulated" } }
};
});
return (
<div>
<div>Hello</div>
<div>
{typeof children === "function"
? children({ childrenArr: manipulatedchildrenArr })
: children}
</div>
</div>
);
};
const App = () => {
const data: Data = { hello: "World" };
return (
<div className="App">
<Tabs items={[<Tab data={data} />]}>
{({ childrenArr }) =>
childrenArr.map(child => (
// Remove "as any" and it will be type unknown and result in an error
<div>{(child.props as any).data.hello}</div>
))
}
</Tabs>
</div>
);
};
type TabProps={
数据?:T;
};
类型TabsProps={
儿童:({
childrenArr
}: {
childrenArr:React.ReactElement[];
})=>React.ReactElement[];
项目:React.ReactElement[];
};
类型数据={hello:string};
常量Tab=({data}:TabProps)=>。。。;
常量选项卡=({children,items}:TabsProps)=>{
const childrenArr=useMoom(()=>(Array.isArray(items)?items:[items])[
项目
]);
// ...
//在实际应用中,这是在childrenArr中操作元素的地方
//因为这只是一个例子,我就这样做
const操纵的childrenArr=childrenArr.map(child=>{
返回{
…(任何儿童),
道具:{数据:{你好:“世界被操纵了”}
};
});
返回(
你好
{typeof children==“函数”
?儿童({childrenArr:manufacturedchildrenarr})
:children}
);
};
常量应用=()=>{
const data:data={hello:“World”};
返回(
{({childrenArr})=>
childrenArr.map(child=>(
//删除“as any”,则其类型未知并导致错误
{(child.props作为任何).data.hello}
))
}
);
};
正如您所看到的,
数据类型
道具丢失。现在我不确定我是否超出了您所寻找的范围,如果超出了范围,请告诉我,我将调整解决方案
更新:我忘了为单个选项卡添加代码
import React from "react";
import ReactDOM from "react-dom";
export interface ITabProps<T> {
data?: T;
handleProcessData: (data: T) => string;
}
export function Tab<T>(props: ITabProps<T>) {
const data = props.data ? props.handleProcessData(props.data) : "None";
return <div>Hello {data}</div>;
}
export type TabElement<T> = React.ReactElement<ITabProps<T>> | React.ReactElement<ITabProps<T>>[]
export interface ITabsProps<T> {
handleManipulation: (data: T) => T;
children: TabElement<T>
}
export function Tabs<T>(props: ITabsProps<T>) {
const array = [] as TabElement<T>[];
if (Array.isArray(props.children))
props.children.forEach((child) => {
let mChild = <Tab<T> handleProcessData={child.props.handleProcessData} data={props.handleManipulation(child.props.data)} /> as TabElement<T>;
array.push(mChild)
})
else {
let mChild = <Tab<T> handleProcessData={props.children.props.handleProcessData} data={props.handleManipulation(props.children.props.data)} /> as TabElement<T>;
array.push(mChild)
}
return <div>{array.map((item) => (item))}</div>;
}
export type Data = { hello: string };
export function App() {
//B.C. it's generic you going to have to have some form of generic control functions
const handleProcessData = (data: Data) => {
//Here you have to specifiy how this specific data type is processed
return data.hello;
};
const handleManipulation = (data: Data) => {
//here you would have all your manipulation logic
return { hello: data.hello + " is manipulated" };
}
//To Make this easier to use you could nest handleProcessData inside the Tabs component
return (
<div>
<Tabs<Data> handleManipulation={handleManipulation}>
<Tab<Data> handleProcessData={handleProcessData} data={{hello: "world1"}} />
<Tab<Data> handleProcessData={handleProcessData} data={{hello: "world2"}} />
</Tabs>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
从“React”导入React;
从“react dom”导入react dom;
导出接口ITabProps{
数据?:T;
handleProcessData:(数据:T)=>字符串;
}
导出功能选项卡(道具:ITabProps){
const data=props.data?props.handleProcessData(props.data):“无”;
返回Hello{data};
}
导出类型TabElement=React.ReactElement | React.ReactElement[]
导出接口ITabsProps{
手部操作:(数据:T)=>T;
子元素:TabElement
}
导出功能选项卡(道具:ITabsProps){
常量数组=[]作为TabElement[];
if(Array.isArray(props.children))
props.children.forEach((child)=>{
设mChild=as TabElement;
array.push(mChild)
})
否则{
设mChild=as TabElement;
array.push(mChild)
}
返回{array.map((item)=>(item))};
}
导出类型数据={hello:string};
导出函数App(){
//B.C.它是通用的,你必须有某种形式的通用控制函数
常量handleProcessData=(数据:数据)=>{
//这里您必须指定如何处理此特定数据类型
返回data.hello;
};
常量句柄操作=(数据:数据)=>{
//在这里,您将拥有所有的操作逻辑
返回{hello:data.hello+“被操纵”};
}
//为了使其更易于使用,您可以将handleProcessData嵌套在Tabs组件中
返回(
);
}
render(,document.getElementById(“根”));
我现在正在研究一个解决方案,但是,您可以添加更多关于此代码最终目标的详细信息?顺便说一句,这可能会对您有所帮助,@Nicholas_Jones cool。使用data prop的原因是,我有时需要使用其中的数据在从render props传回自定义选项卡标签后有条件地呈现该标签。这就是为什么我将其存储在组件的属性中。通过渲染道具发送的原因是,在这种情况下,将元素拆分为多个元素数组,如可见/下拉(用于溢出选项卡)等。期待看到您的解决方案!感谢您抽出时间提出此解决方案。确实学会了一些技巧。很抱歉,如果我不太清楚我想要实现什么,但实际上我将把子数组分成可见和溢出部分,但是我也将根据数据属性中的内容(如果有)以不同的方式呈现标签。因此,这与其说是改变数据属性,不如说是基于给定子元素/选项卡元素的数据对象中的内容对子元素进行更改。问题是,当试图使用渲染道具实现这一点时,数据会丢失其类型