什么时候使用 JSX.Element、ReactNode 和 ReactElement? [英] When to use JSX.Element vs ReactNode vs ReactElement?

查看:37
本文介绍了什么时候使用 JSX.Element、ReactNode 和 ReactElement?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

  1. JSX.ElementReactNodeReactElement 有什么区别?
  2. 为什么类组件的render方法返回ReactNode,而功能组件返回ReactElement?
  3. 如何解决 null 的问题?

解决方案

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

ReactElement 是一个具有类型和属性的对象.

 type Key = string |数字interface ReactElement<P = any, T extends string |JSXElementConstructor<任何>= 字符串 |JSXElementConstructor<任何>{类型:T;道具:P;键:键 |空值;}

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

type ReactText = string |数字;类型 ReactChild = ReactElement |反应文本;接口 ReactNodeArray 扩展了 Array{}输入 ReactFragment = {} |反应节点阵列;类型 ReactNode = ReactChild |反应片段 |反应门户 |布尔值 |空|不明确的;

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

声明全局{命名空间 JSX {interface Element 扩展了 React.ReactElement{ }}}

举例:

 

//<- ReactElement = JSX.Element<自定义>//<- ReactElement = JSX.Element{真&&测试"}//<- ReactNode</自定义></p>

<块引用>

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

确实,它们确实返回了不同的东西.组件的返回:

 render(): ReactNode;

函数是无状态组件":

 interface StatelessComponent

{(props: P & { children?: ReactNode }, context?: any): ReactElement |空值;//... 没关系}

这实际上是由于历史原因.

<块引用>

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

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

类型来源

I am currently migrating a React application to TypeScript. So far, this works pretty well, but I have a problem with the return types of my render functions, specifically in my functional components.

I have always used JSX.Element as the return type, now this doesn't work any more if a component decides to not render anything, i.e. returns null, since null is not a valid value for JSX.Element. This was the beginning of my journey. I searched the web and found that you should use ReactNode instead, which includes null and a few other things that can happen.

However, when creating a functional component, TypeScript complains about the ReactNode type. Again, after some searching I found, that for functional components you should use ReactElement instead. However, if I do so, the compatibility issue is gone, but now TypeScript again complains about null not being a valid value.

To cut a long story short, I have three questions:

  1. What is the difference between JSX.Element, ReactNode and ReactElement?
  2. Why do the render methods of class components return ReactNode, but functional components return ReactElement?
  3. How do I solve this with respect to null?

解决方案

What is the difference between JSX.Element, ReactNode and ReactElement?

A ReactElement is an object with a type and props.

 type Key = string | number

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

A ReactNode is a ReactElement, a ReactFragment, a string, a number or an array of ReactNodes, or null, or undefined, or a boolean:

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 is a ReactElement, with the generic type for props and type being any. It exists, as various libraries can implement JSX in their own way, therefore JSX is a global namespace that then gets set by the library, React sets it like this:

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

By example:

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

Why do the render methods of class components return ReactNode, but function components return ReactElement?

Indeed, they do return different things. Components return:

 render(): ReactNode;

And functions are "stateless components":

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

This is actually due to historical reasons.

How do I solve this with respect to null?

Type it as ReactElement | null just as react does. Or let Typescript infer the type.

source for the types

这篇关于什么时候使用 JSX.Element、ReactNode 和 ReactElement?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆