ReactNode

リアクトノード

Next.js

Next.js の公式ドキュメントには次のようなソースコードが記述されています。

export default function DashboardLayout({
  children, // will be a page or nested layout
}: {
  children: React.ReactNode
}) {
  return (
    <section>
      <nav></nav>
      {children}
    </section>
  )
}

しかし、このソースコードを見ても、React.ReactNode という型が何を意味しているのかは分かりません。そこで、この記事では React.ReactNode について解説します。

ReactNode を分かりやすく

ReactNode は、TypeScript で React を使用する際に頻繁に遭遇する子要素を扱う際の型の一つです。React の JSX 要素を扱うための型として定義されており、React エレメント、文字列、数値、配列、null、undefined、boolean など、コンポーネント内で扱う要素の範囲を広げることが可能になります。その柔軟性から、React のコンポーネント設計において、子要素を扱う際の型としてよく使用されます。

具体的な型定義は以下のようになります。

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

ReactNode を使うメリット

ReactNode の最大のメリットは、その包括的な型定義により、React コンポーネント内で扱うことのできる値の範囲が広がる点です。

例えば、子コンポーネントを受け取る親コンポーネントを設計する際、子コンポーネントの型を具体的なコンポーネントの型(例えば、特定の関数コンポーネントの型)に限定してしまうと、その親コンポーネントは限定された子コンポーネントしか受け付けません。しかし、子コンポーネントの型を ReactNode にすることで、文字列や数値、更には JSX 要素(つまり、React コンポーネント)など、幅広い種類の子要素を受け取ることが可能になります。

ReactNode を実装

それでは、ReactNode を用いた具体的な実装例を見てみましょう。以下のコードは、子要素を ReactNode として受け取るカードコンポーネントの例です。

type CardProps = {
  title: string
  children: React.ReactNode
}

const Card = ({ title, children }: CardProps) => (
  <div className="card">
    <h2>{title}</h2>
    <div>{children}</div>
  </div>
)

この Card コンポーネントは title プロパティに加えて、任意の子要素(children)を受け取ります。この children の型が ReactNode と定義されているため、この Card コンポーネントは、文字列、数値、さらには別の React コンポーネントなど、様々な形式の子要素を受け取ることが可能になります。

たとえば、以下のように使用することができます。

const MyPage = () => (
  <div>
    <Card title="数値の表示">{123}</Card>
    <Card title="テキストの表示">{'Hello, world!'}</Card>
    <Card title="コンポーネントの表示">
      <MyComponent />
    </Card>
  </div>
)

const MyComponent = () => <div>これは MyComponent です。</div>

このように、ReactNode を用いることで、柔軟な子要素の受け取りが可能となり、コンポーネント設計の幅が大きく広がります。

ReactNode の注意点

一方で、ReactNode のような包括的な型は、その柔軟性から型チェックの意義を一部失う可能性があります。型システムの主な目的の一つは、期待しないデータの処理を防ぐことです。しかし、ReactNode は広範な値を許容するため、型チェックが緩やかになります。そのため、特定の型を期待する場合(例えば、特定の関数コンポーネントのみを受け取りたい場合)は、より具体的な型を使用することが推奨されます。

以上が ReactNode の基本的な説明と使用例です。その包括的な型定義により、コンポーネント設計の幅が大きく広がる ReactNode ですが、その一方で型安全性には注意が必要です。コンポーネント設計時には、どの程度の柔軟性を求め、どの程度の型安全性を保つべきかを考慮しながら、適切な型を選択していきましょう。