何时使用 JSX.Element、ReactNode、ReactElement?

新手上路,请多包涵

我目前正在将 React 应用程序迁移到 TypeScript。到目前为止,这工作得很好,但是我的 render 函数的返回类型有问题,特别是在我的功能组件中。

我一直使用 JSX.Element 作为返回类型,现在如果组件决定 渲染任何东西,这将不再起作用,即返回 null ,因为 null 不是 JSX.Element 的有效值。这是我旅程的开始。我在网上搜索,发现您应该使用 ReactNode 代替,其中包括 null 以及其他一些可能发生的事情。

但是,在创建功能组件时,TypeScript 会抱怨 ReactNode 类型。再次,经过一番搜索,我发现,对于功能组件,您应该使用 ReactElement 代替。但是,如果我这样做,兼容性问题就消失了,但现在 TypeScript 再次抱怨 null 不是有效值。

长话短说,我有三个问题:

  1. JSX.Element , ReactNodeReactElement 什么区别?
  2. 为什么类组件的 render 方法返回 ReactNode ,而功能组件返回 ReactElement
  3. 关于 null 我该如何解决这个问题?

原文由 Golo Roden 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.5k
2 个回答

JSX.Element、ReactNode 和 ReactElement 有什么区别?

ReactElement 是具有类型和道具的对象。

  type Key = string | number

 interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
    type: T;
    props: P;
    key: Key | null;
}

ReactNode 是一个 ReactElement、一个 ReactFragment、一个字符串、一个数字或一个 ReactNode 数组,或者是 null,或者 undefined,或者是一个布尔值:

 type ReactText = string | number;
type ReactChild = ReactElement | ReactText;

interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

JSX.Element 是一个 ReactElement,props 的泛型类型是 any。它存在,因为各种库可以以自己的方式实现 JSX,因此 JSX 是一个全局名称空间,然后由库设置,React 设置它是这样的:

 declare global {
  namespace JSX {
    interface Element extends React.ReactElement<any, any> { }
  }
}

举例:

  <p> // <- ReactElement = JSX.Element
   <Custom> // <- ReactElement = JSX.Element
     {true && "test"} // <- ReactNode
  </Custom>
 </p>

为什么类组件的render方法返回ReactNode,而函数组件返回ReactElement?

事实上,它们确实返回了不同的东西。 Component 返回:

  render(): ReactNode;

函数是“无状态组件”:

  interface StatelessComponent<P = {}> {
    (props: P & { children?: ReactNode }, context?: any): ReactElement | null;
    // ... doesn't matter
}

这其实是由于 历史原因

关于null,我该如何解决这个问题?

输入为 ReactElement | null 就像 react 一样。或者让 Typescript 推断类型。

类型的来源

原文由 Jonas Wilms 发布,翻译遵循 CC BY-SA 4.0 许可协议

ReactElement 是 React 中元素的类型,可以通过 JSXReact.createElement 创建。

 const a = <div/> // this is a ReactElement

ReactNode 更广泛,它可以是文本、数字、布尔值、null、未定义、门户、ReactElement 或 ReactNode 数组。它代表 React 可以渲染的任何东西

 const a = (
  <div>
     hello {[1, "world", true]} // this is a ReactNode
  </div>
)

JSX.Element 是 Typescript 的内部钩子。它 设置为等于 ReactElement 以告诉 Typescript 每个 JSX 表达式都应该被键入为 ReactElements。但是如果我们使用 Preact,或者其他使用 JSX 的技术,它就会被设置为其他东西。

功能组件 返回 ReactElement | null ,因此它不能返回裸字符串或 ReactElements 数组。这是一个 已知限制。解决方法是使用 Fragments

 const Foo: FC = () => {
  return <>hello world!</>  // this works
}

类组件的 渲染函数返回 ReactNode ,所以应该没有问题。

原文由 Emmanuel Meric de Bellefon 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题