TL;DR
このページでは、ReactNode
の実装方法について解説しますね。一言で言うとReactNode
とは、React のコンポーネントのレンダリングに使用できる任意の型を表現するための用語です。
開発環境 | バージョン |
---|---|
Next.js | 13.4.4 |
TypeScript | 5.0.4 |
Emotion | 11.11.0 |
React | 18.2.0 |
ReactNode の要点
要点をまとめると以下のようになります。
- React コンポーネントが子要素(children)として受け入れることができるデータ型を表す
- 文字列、数値、React コンポーネント、配列、null、undefined など、多岐にわたる型を包括する
- TypeScript で React コンポーネントを定義する際に、
ReactNode
は子要素の型定義としてよく使われる
したがって、ReactNode
を用いてコンポーネントの props を定義すると、そのコンポーネントは任意の子要素を受け入れることができます。この柔軟性が React の強力な機能の一つとなっています。
どのような型を持つことができるか
ReactNode は、React の要素(Element)を表現するための用語で、React のコンポーネントツリーを形成します。ReactNode は次のいずれかの型を持つことができます。
boolean
null
undefined
number
string
ReactElement
(React コンポーネント自体)ReactFragment
(複数の子要素をまとめる)ReactPortal
(レンダリングされる DOM を特定の場所に設定する)Array<ReactNode>
(ReactNode の配列)
つまり、ReactNode は非常に柔軟で、文字列や数値といったプリミティブ型から、React コンポーネントまで様々な型を含むことができます。これにより、複雑な UI 構造をツリー形式で表現し、それをブラウザ上でレンダリングすることができます。
type Props = {
children: React.ReactNode
}
const Component = ({ children }: Props) => {
return <div>{children}</div>
}
const App = () => {
return (
<Component>
<h1>Hello, world!</h1>
</Component>
)
}
この基本的なソースコードでは、Component
という新しいコンポーネントを定義しています。ここでchildren
というプロパティは、ReactNode の型を持ちます。このchildren
は、<Component>
タグの開始タグと終了タグの間に配置された任意の React ノードを表します。
interface で ReactNode を定義する
interface
を使ってReactNode
を含む props を定義することも可能です。ReactNode
は任意の子要素を表す型なので、以下のような形でコンポーネントの props を定義できます。
interface MyComponentProps {
children: React.ReactNode
}
const MyComponent = ({ children }: MyComponentProps) => {
return <div>{children}</div>
}
この例では、MyComponent
は任意の子要素を受け入れ、それをdiv
要素の中でレンダリングします。この子要素はReactNode
型として定義されているので、テキスト、他の React コンポーネント、配列など、あらゆる種類の React 要素を受け入れます。
children として受け入れることができるデータ型
ReactNode
は React コンポーネントが子要素(children)として受け入れることができるデータ型を表現します。子要素とは、コンポーネントを利用する際にその開始タグと終了タグの間に配置される要素のことです。
<Component>{/* ここに配置される要素が子要素(children) */}</Component>
React の子要素は非常に柔軟で、単純な文字列や数値から、React コンポーネント自体、配列、null や undefined まで、様々な型を含むことができます。これらすべての可能性を包含する型としてReactNode
が提供されています。
例えば、以下のようなMyComponent
コンポーネントを考えてみましょう。
type Props = {
children: React.ReactNode
}
const MyComponent = ({ children }: Props) => {
return <div>{children}</div>
}
const App = () => {
return (
<MyComponent>
<h1>Hello, world!</h1>
<p>Welcome to my app.</p>
</MyComponent>
)
}
上記の例では、MyComponent
はchildren
という名前の props を受け入れます。このchildren
はReactNode
型で、<MyComponent>
タグの開始タグと終了タグの間にあるすべての内容を含みます。この場合、<h1>Hello, world!</h1>
と<p>Welcome to my app.</p>
がその子要素となります。
ReactChild との違い
ReactChild
とReactNode
は、React の型システムにおける重要な型で、それぞれ異なる種類の React 要素を表現します。
ReactChild
ReactChild
は、React コンポーネントがレンダリングできる要素のうち最も基本的な型を表します。具体的には、ReactChild
はReactElement
またはstring
またはnumber
型を取ります。
つまり、単一の React コンポーネント、文字列、または数値はReactChild
として扱うことができます。
ReactNode
一方で、ReactNode
は React がレンダリング可能なすべての種類の値を表します。具体的には、ReactNode
は以下の値を取ることができます。
ReactChild
(すなわち、ReactElement
、string
、number
)boolean
(通常、これは意図的にレンダリングされませんが、条件付きレンダリングの結果として生じることがあります)null
(意図的に何もレンダリングしないことを示す)undefined
(意図的に何もレンダリングしないことを示す)ReactFragment
(複数の子要素をグループ化する)ReactPortal
(コンポーネントツリーの外部にレンダリングする)- 配列(これは複数の
ReactNode
要素のリストを指す)
したがって、ReactNode
はReactChild
よりも幅広い範囲の要素をカバーします。これは、ある React コンポーネントのchildren
props の型としてよく使われます。これは、そのコンポーネントが任意の子要素(文字列、別のコンポーネント、配列、など)を受け入れることができることを示します。
ReactText
ReactText
は React の型システムにおける基本的な型で、文字列 (string
) または数値 (number
) のどちらかを表します。これは、React がテキストノードとしてレンダリングできる唯二の JavaScript の原始的なデータ型を表しています。
具体的には、次のようなコンポーネントがあります。
const MyComponent = () => {
return (
<div>
Hello, world! // これはReactTextです (string)
{2023} // これもReactTextです (number)
</div>
)
}
上記の例では、"Hello, world!"と 2023 は、どちらもReactText
として扱われます。これらは、どちらもブラウザにレンダリングされた時にはテキストノードとして表示されます。
それに対して、ReactChild
はReactText
とReactElement
のどちらかを表し、ReactNode
はReactChild
、boolean
、null
、undefined
、ReactFragment
、ReactPortal
、または配列を表します。したがって、これらの型は React の要素や子要素を扱う際の複雑さを表現するために存在します。
とどのつまり、ReactNode
は最も包括的な型であり、React コンポーネントの子要素として渡すことができるほとんど全てのものをカバーします。つまり、ReactElement
(これが一般的な JSX 要素です)、文字列、数値、boolean、null、undefined、React フラグメント、React ポータル、そしてこれら全てを含む配列などが含まれます。
したがって、React コンポーネントの子要素として許容したいもの全てを許容する場合には、ReactNode
を使用すると良いでしょう。ただし、特定の型の子要素のみを許容したい場合(例えば、特定の React コンポーネントのみ、または文字列のみなど)には、より具体的な型を使用することもあります。
Next.js で、ReactNode を実装
続いて Next.js のコンテクストで、ReactNode を用いた実装例を見ていきましょう。
/components/MyComponent.tsx
:
import React from 'react'
type Props = {
children: React.ReactNode
}
const MyComponent = ({ children }: Props) => {
return <div>{children}</div>
}
export default MyComponent
上記のMyComponent.tsx
では、ReactNode を活用したコンポーネントを定義しています。ReactNode 型のchildren
プロパティは、<MyComponent>
タグの開始タグと終了タグの間に配置された任意の React ノードを表現します。
次に、このMyComponent
を使ってページコンポーネントを作成します。
/pages/index.tsx
:
import MyComponent from '../components/MyComponent'
const HomePage = () => {
return (
<MyComponent>
<h1>Welcome to My Site</h1>
<p>This is a sample text.</p>
</MyComponent>
)
}
export default HomePage