Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use JSX.Element vs ReactNode vs ReactElement?

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?
like image 611
Golo Roden Avatar asked Sep 26 '19 19:09

Golo Roden


People also ask

What is the difference between ReactNode and ReactElement?

ReactElement is the type for elements in React, either created via JSX or React. createElement. ReactNode is wider, it can be text, number, boolean, null, undefined, a portal, a ReactElement, or an array of ReactNodes. It represents anything that React can render.

What is JSX element type?

JSX is an embeddable XML-like syntax. It is meant to be transformed into valid JavaScript, though the semantics of that transformation are implementation-specific. JSX rose to popularity with the React framework, but has since seen other implementations as well.

Should I use JSX With React native?

React doesn't require using JSX, but most people find it helpful as a visual aid when working with UI inside the JavaScript code. It also allows React to show more useful error and warning messages. With that out of the way, let's get started!

What is ReactNode?

A React node is defined as: a light, stateless, immutable, virtual representation of a DOM node. React nodes are not real DOM nodes (e.g., text or element nodes) themselves, but a representation of a potential DOM node. The representation is considered the virtual DOM.


1 Answers

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

like image 122
Jonas Wilms Avatar answered Sep 20 '22 19:09

Jonas Wilms