LoginSignup
23
13

More than 3 years have passed since last update.

Reactのchildren探訪

Posted at

ReactのJSXでも子要素を定義できますが、これが結構面白いものでした。

自作エレメントにも子要素

ReactのJSXでは、(DOMを組み立てるものである以上当然ですが)<div>の中に<a>を書いて、そしてさらに文字列を書き込む、ということが可能です。

そして、これはHTML由来のエレメントだけでなく、自作のコンポーネントでも実現可能です。

function SomeWrapper({children}) {
  return(
    <div className="some-class">
      { children }
    </div>
  );
}

このように、子要素はchildrenというPropとして渡ってきます。

childrenの中身が知りたくて

では、このchildrenには何がどのような形式で来るのでしょうか。JSXの変換先であるReact.createElementソースコードに当たってみました。挙動はchildrenの数によって違います。

  • 0個…childrenにはpropとして渡したchildrenが(もしあれば)渡される
  • 1個…childrenには唯一のchildren引数がそのまま渡される1
  • 2個以上…childrenには引数で渡されたものが配列に詰め込まれる

公式な操作方法

現実問題として、今からchildrenの実装を変えてしまうということは互換性問題などを考えれば可能性は薄いのですが、公式にはchildrenのデータ形式は「非公開」ということになっています。そこで、childrenを操作するためのReact.Childrenというユーティリティ関数群があります(リファレンス)。

  • React.Children.mapchildrenの各要素に対して関数を実行して、結果を配列で得る。
  • React.Children.forEachchildrenの各要素に対して関数を実行する。
  • React.Children.countchildrenの個数を返す
  • React.Children.toArraychildrenを本物の配列に変換して返す
  • React.Children.onlychildrenが1つのJSXエレメントであることを保証する

なお、forEachmaptoArrayで処理する際に、キーは子要素間で一意となるようなものがReact側で振られます。また、子要素として<React.Fragment>を渡した場合、1つものとして扱われます。

childrenReact.memo

今のところ、React.createElementをキャッシュするような仕組みはないので、<br />のようなシンプルなJSX要素であっても、2回の実行でオブジェクトとして一致することはありません。さらに、上述のように複数の子要素をもたせた場合、childrenの配列を生成しますので、このインスタンスも一致しません。

そして、PureComponentReact.memochildrenを特別扱いしませんので、(文字列1つだけ指定するような例外的なケースは別として)childrenを指定するようなコンポーネントでは、メモ化は利かないということになってしまいます。

対策としては、

  • 子要素を取るコンポーネントを使う側の場合、「コンポーネント+子要素」全体を1つのコンポーネントとして、それをメモ化する
  • 子要素を取るコンポーネントを作る場合、メモ化を諦める

などが考えられます。そして、children以外でも、表示する文字列をpropで取る場合に、「HTMLタグで装飾したい」とその場で書いたJSXを渡せば同じ事態となります。こちらについては、React.useMemo、クラスのプロパティ、外側で変数に定義するなど、同じJSXインスタンスを使い回す形として対応が可能かと思います。


  1. Context.Consumerなどで子要素代わりにコールバックを書くことがありますが、1個なので関数がそのままchildrenに入る形となっています。 

23
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
13