前回の最後に、コンポーネント自体はReact要素なのかという疑問を投げかけました。今回はそれを実際に確認していきます。
結論から言うと、コンポーネントもReact要素です。
変換結果を見てみる
まず、HTMLタグの場合はこうでした。
<h3>Hello World</h3>
_jsx("h3", { children: "Hello World" });
では、Greet.tsxのようにコンポーネントを読み込んだ場合はどうなるでしょうか。
//Greet.tsx
const Greet = ()=> {
return (
<div className="component">
<List color="red" />
</div>
);
}
_jsx("div", {
className: "component",
children: _jsx(List, { color: "red" }),
});
childrenのところに、Listコンポーネントの_jsx()が設定されています。
React要素とは「この関数によって作成されるオブジェクト」のことなので、コンポーネント自体も最終的にはReact要素に変換される、ということが分かります。
コンソールで確認する
実際にコンソールで見てみましょう。
//Greet.tsx
import "./Greet.css"
import List from "./List"
const Greet = ()=> {
const sample = (
<div className="component">
<List color="red" />
</div>
);
console.log(sample);
return sample;
}
export default Greet;
一番上の階層はdivタグなので、typeがdivになっています。
そしてpropsのchildrenのところにListコンポーネントが設定されているはずです。開いてみましょう。
typeのところに関数が設定されていて、nameにはListと入っています。これは関数コンポーネントの名前です。
つまりHTMLタグのときはtypeに"div"のような文字列が入り、コンポーネントのときはtypeに関数そのものが入るわけです。
Reactはこの関数を実行し、返ってきたTSXがまたReact要素になって、という再帰的な構造をとっていきます。
React要素のツリーで考える
いま作っているアプリの構造を思い出してみましょう。
//page.tsx
import Greet from "../components/Greet";
const Home = ()=> {
return (
<Greet />
);
}
export default Home;
HomeがGreetを読み込み、GreetがListを読み込んでいます。このときのReact要素のツリーはこうなります。
Home のReact要素
└── Greet のReact要素
└── div のReact要素
├── h3 のReact要素
└── List のReact要素
└── ul のReact要素
1つ1つの要素がReact要素であり、そこにはTSXのタグから作られるReact要素とコンポーネントから作られるReact要素が混在しています。
ですのでReactの内部では、コンポーネントもReact要素として扱っているということを覚えておいてください。
コンポーネントツリー
なぜこれをわざわざ紹介したかというと、コンポーネントを含むこのツリーのほうが、React内部で保持されているデータ構造により近い形になるためです。
先ほどのツリーから、コンポーネントだけを抽出するとこうなります。
Home
└── Greet
└── List
このコースでは、
- React要素のツリー
- そこからコンポーネントだけを抽出したコンポーネントツリー
この2つを使ってReactの挙動を説明していきます。コンポーネントツリーという単語は以降よく出てくるので、ぜひ覚えておいてください。
余談:Fiber
ここからは余談なので、力を抜いて読んでいただければと思います。
Reactの内部では、React要素のツリーから作成したFiberツリーという別のツリーを用いて状態管理を行っています。その1つ1つの要素はFiberノードと呼ばれ、React要素とほぼ1対1の関係になります。
少し難しい内容ですし、覚えなくてもReact自体は問題なく使えるようになります。興味のある方はReact Fiberという単語で調べてみてください。
確認問題
以下の3つのファイルがあるとします。
//page.tsx
import Greet from "../components/Greet";
const Home = ()=> {
return (
<Greet />
);
}
export default Home;
//Greet.tsx
import Container from "./Container"
import List from "./List"
const Greet = ()=> {
return (
<div className="component">
<Container>
<List />
</Container>
</div>
);
}
export default Greet;
//Container.tsx
const Container = ({ children }: ContainerProps)=> {
return (
<div className="box">{children}</div>
);
}
export default Container;
問題
-
<Container>が変換されたあとの関数呼び出しを書いてください - そのReact要素の
typeには何が入るか答えてください - このアプリのコンポーネントツリーを書いてください
(下に解答を記載しています)
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
解答
1. 変換後の関数呼び出し
_jsx(Container, { children: _jsx(List, {}) });
2. typeに入るもの
Containerという関数そのものが入ります。
HTMLタグのときは"div"のような文字列が入りますが、コンポーネントのときは関数が入る、というのが違いです。
3. コンポーネントツリー
Home
└── Greet
└── Container
└── List
React要素のツリーにはHTMLタグ由来のdivやulも含まれますが、そこからコンポーネントだけを抽出するとこの形になります。
チェックリスト
- コンポーネントもReact要素になると説明できる
-
HTMLタグは
typeが文字列、コンポーネントはtypeが関数だと区別できる - React要素のツリーには、タグ由来とコンポーネント由来の要素が混在している
- Reactが関数を実行し、返ってきたTSXを辿っていく再帰的な構造を理解している
- コンポーネントツリーがReact要素のツリーからコンポーネントだけを抜き出したものだと分かっている
- コンポーネントツリーという単語を以降のレクチャーで使うと知っている
- Fiberという仕組みがあることを名前だけ知っている
第十四回はここまで。
次回はこのセクションで学んだ内容を踏まえて、より深掘りをしていきます。