是否有用于 React Function 组件的类型,包括返回片段、空值、字符串等?
Posted
技术标签:
【中文标题】是否有用于 React Function 组件的类型,包括返回片段、空值、字符串等?【英文标题】:Is there a typing for React Function components that includes returning fragments, nulls, strings etc? 【发布时间】:2021-09-16 18:19:52 【问题描述】:我的问题是对这个高度赞成的问题的澄清/更新:
When to use JSX.Element vs ReactNode vs ReactElement?
在我看来,当您想要拥有返回字符串、null 等原语的函数组件时,TypeScript 并不能很好地发挥作用。
例如,假设您有一个需要渲染道具的组件:
import React from "react";
type User =
id: string;
name: string;
imgSrc: string;
type UserProfilePageProps =
RenderUserPanel: React.ComponentType<user: User>;
export const fetchUser = async () : Promise<User> =>
return
id: "123",
imgSrc: "placeholdit",
name: "Joe Bloggs"
const UserProfilePage = (props: UserProfilePageProps) =>
const RenderUserPanel = props;
const [user, setUser] = React.useState<null |User>(null);
React.useEffect(()=>
fetchUser().then(user => setUser(user));
, []);
return <section>
<h2>User Details</h2>
user && <RenderUserPanel user = user/>
</section>
现在我可以创建应该以四种不同方式实现这个渲染属性的组件:
class ClassBasedUserPanel extends React.Component<user: User>
render()
return <div>
this.props.user.name
</div>
class ClassBasedUserPanelThatReturnsString extends React.Component<user: User>
render()
return this.props.user.name;
const FunctionBasedUserPanel = (props: user: User) =>
return <div>
props.user.name
</div>
const FunctionBasedUserPanelThatReturnsString = (props: user: User) =>
return props.user.name;
但是,FunctionBasedUserPnelThatReturnsAString
不适合 React.ComponentType<user: User>;
,因为 React.FunctionComponent
必须返回一个 React.ReactElement
,而字符串不是。
另一方面,React.ClassComponent
没有这个约束。
const Main = () =>
return <div>
<UserProfilePage RenderUserPanel = ClassBasedUserPanel/>
<UserProfilePage RenderUserPanel = ClassBasedUserPanelThatReturnsString/>
<UserProfilePage RenderUserPanel = FunctionBasedUserPanel/>
/* ERROR! */
<UserProfilePage RenderUserPanel = FunctionBasedUserPanelThatReturnsString/>
</div>
基本上,我想要的是一种类型:
type TypeImLookingFor<P = > = React.ComponentType<P> | (props: P) => ReactNode;
这存在吗?有什么理由不应该存在吗?
注意:我目前使用的是 React 16。也许这是在 React 17 或 18 中修复的问题。
【问题讨论】:
【参考方案1】:我现在将为此发布我自己的 React 16 最佳解决方案 - 但我欢迎其他答案,特别是如果 React 17/18 有更新。
按照我的建议扩大类型的问题在于它实际上不起作用。
举个例子:
type TypeImLookingFor<P = > = React.ComponentType<P> | ((props: P) => React.ReactNode);
class ComponentA extends React.Component
render()
return "aaa";
const ComponentB = () =>
return "bbb";
// They do match the type signature
const A: TypeImLookingFor = ComponentA;
const B: TypeImLookingFor = ComponentB;
const Main = () =>
return <div>
<ComponentA/>
/*
'ComponentB' cannot be used as a JSX component.
Its return type 'string' is not a valid JSX element.ts(2786) */
<ComponentB/>
</div>;
也就是说,如果您想以“JSX-y”方式使用函数组件 - 您不能返回字符串、数字等,即使您可以使用类组件来执行此操作。
我认为最好的解决方案是:
-
将函数组件的返回类型明确声明为
React.ReactElement
如果他们返回的是字符串或数字等,请将其包装在片段中
const ComponentC = () : React.ReactElement =>
//Type 'string' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.ts(2322)
return "aaa";
const ComponentD = () : React.ReactElement =>
return <> aaa </>
const Main2 = () =>
return <div>
<ComponentA/>
<ComponentD/>
</div>;
【讨论】:
以上是关于是否有用于 React Function 组件的类型,包括返回片段、空值、字符串等?的主要内容,如果未能解决你的问题,请参考以下文章
React 组件之 Component PureComponent Function Component