reactjs - 是否有用于 React Function 组件的类型,包括返回片段、空值、字符串等?
问题描述
我的问题是对这个高度赞成的问题的澄清/更新:
何时使用 JSX.Element、ReactNode、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 中修复的问题。
解决方案
我现在将为此发布我自己的 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>;
}
推荐阅读
- php - 如何将数组-de -en -es的每个值添加到末尾?
- php - php自动逐页递增
- javascript - 每次发送请求时检索轮询 URL - Socket.io
- c++ - 通过成员初始化器列表初始化的对象的数据成员的值是多少。具体来说 x 和 y 的值是多少?
- javascript - Yarn Workspaces 和 Browserify - 子文件夹中的 package.json 会破坏构建
- java - com.here.android.mpa.search.PlaceRequest 不能强制转换为 java.io.Serializable
- tensorflow - 为什么我下面修改的 vgg-16 Keras 模型需要 1 小时才能运行一个 epoch
- linux - 如果 bash 脚本的条件有什么问题
- ruby-on-rails - Rails/Date:不要在 Date 对象上使用 `to_time`
- docker - 如何在 Docker 中安装私有依赖项