Closed4
【メモ】ReactElement?ReactNode?React.FC?JSX.Element??

Reactの1要素を表す型ってめちゃめちゃある
それぞれの違いが気になったので軽く調べてまとめてみる
知りたいこと
- ReactElement、ReactNode、React.FC、JSX.Elementの違いって何?
- みんな使い分けたりしてるの?

検索して1分、ドンピシャな記事があった.....

記事を読みつつ自分なりにまとめてみる
ReactNode, ReactElementの違い
ReactElementのコード
/**
* Represents a JSX element.
*
* Where {@link ReactNode} represents everything that can be rendered, `ReactElement`
* only represents JSX.
*
* @template P The type of the props object
* @template T The type of the component or tag
*
* @example
*
* ```tsx
* const element: ReactElement = <div />;
* ```
*/
interface ReactElement<
P = unknown,
T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>,
> {
type: T;
props: P;
key: string | null;
}
ReactNodeのコード
/**
* Different release channels declare additional types of ReactNode this particular release channel accepts.
* App or library types should never augment this interface.
*/
interface DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES {}
/**
* Represents all of the things React can render.
*
* Where {@link ReactElement} only represents JSX, `ReactNode` represents everything that can be rendered.
*
* @see {@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet}
*
* @example
*
* ```tsx
* // Typing children
* type Props = { children: ReactNode }
*
* const Component = ({ children }: Props) => <div>{children}</div>
*
* <Component>hello</Component>
* ```
*
* @example
*
* ```tsx
* // Typing a custom element
* type Props = { customElement: ReactNode }
*
* const Component = ({ customElement }: Props) => <div>{customElement}</div>
*
* <Component customElement={<div>hello</div>} />
* ```
*/
// non-thenables need to be kept in sync with AwaitedReactNode
type ReactNode =
| ReactElement
| string
| number
| bigint
| Iterable<ReactNode>
| ReactPortal
| boolean
| null
| undefined
| DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[
keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES
]
| Promise<AwaitedReactNode>;
* Where {@link ReactNode} represents everything that can be rendered, `ReactElement`
* only represents JSX.
ReactNode は「描画可能なものすべて」(文字列、数値、ReactElementなど)を表すのに対し、
ReactElement は「JSXとして記述された要素」だけを表す。らしい
つまりこういうこと。ReactNode
のほうがより広い型になっている。
const a = "Hello"; // 文字列
const b = 123; // 数値
const c = null; // null
const d = <div>Hi</div>; // JSX(ReactElement)
const e = ["a", 1, null]; // 配列
const node_a: ReactNode = a; // ✅ OK
const node_b: ReactNode = b; // ✅ OK
const node_c: ReactNode = c; // ✅ OK
const node_d: ReactNode = d; // ✅ OK
const node_e: ReactNode = e; // ✅ OK
const element_a: ReactElement = a; // ❌️ 型 'string' を型 'ReactElement<unknown, string | JSXElementConstructor<any>>' に割り当てることはできません。
const element_b: ReactElement = b; // ❌️ 型 'number' を型 'ReactElement<unknown, string | JSXElementConstructor<any>>' に割り当てることはできません。
const element_c: ReactElement = c; // ❌️ 型 'null' を型 'ReactElement<unknown, string | JSXElementConstructor<any>>' に割り当てることはできません。
const element_d: ReactElement = d; // ✅ OK
const element_e: ReactElement = e; // ❌️ 型 '(string | number | null)[]' には 型 'ReactElement<unknown, string | JSXElementConstructor<any>>' からの次のプロパティがありません: type, props, key
React.FC
コード
/**
* Represents the type of a function component. Can optionally
* receive a type argument that represents the props the component
* receives.
*
* @template P The props the component accepts.
* @see {@link https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet}
* @alias for {@link FunctionComponent}
*
* @example
*
* ```tsx
* // With props:
* type Props = { name: string }
*
* const MyComponent: FC<Props> = (props) => {
* return <div>{props.name}</div>
* }
* ```
*
* @example
*
* ```tsx
* // Without props:
* const MyComponentWithoutProps: FC = () => {
* return <div>MyComponentWithoutProps</div>
* }
* ```
*/
type FC<P = {}> = FunctionComponent<P>;
* Represents the type of a function component. Can optionally
* receive a type argument that represents the props the component
* receives.
関数コンポーネントの型を表します。オプションで、そのコンポーネントが受け取る props の型を型引数として指定することができます。
ということなので関数型コンポーネントを表すのがReact.FC
const MyComponent: React.FC<{ title: string }> = ({ title }) => {
return <h1>{title}</h1>;
};
JSX.Element
そもそもJSXとはなにかというと
JSX(JavaScript XML)は、コンポーネント指向のJavaScriptライブラリやフレームワーク(特にReact)で一般的に採用されている、JavaScriptの拡張構文です。JSXを用いると、JavaScriptのコード内にHTMLタグのような構文が埋め込み可能となり、より直感的かつ読みやすい形でUIのコードを表現することができます。
とのこと
ただコードをみると その実態はReactElementになっているみたい?
namespace JSX {
interface Element extends React.ReactElement<any, any> {}
余談
余談だがReact19だとReact.JSX.Element
で参照するようになっていた、もともとJSX.Elementだったはずだけど ...
ってことは先程調べた結果がそのまま使えそう
つまりReactElement
から型引数をなくしたものがJSX.Element
ということか

まとめ
-
ReactNode
は「描画可能なものすべて」(文字列、数値、ReactElementなど) -
ReactElement
は「JSXとして記述された要素」 -
React.FC
は関数型コンポーネント -
JSX.ElementはReactElement
の2つの型引数をanyで代入したもの - 状況に応じて使い分けることはできそう
このスクラップは6ヶ月前にクローズされました