Reactを使用していて、「{ }ってどこで使えるんだっけ?」「あれ、ここにこれ書いちゃいけないんだっけ?」「何でこれエラーになるの?」「結局JSXって何?」と細かく理解しないまま使っていた為につまずくことが多かった。
そこで、改めて基礎を理解しようと思って記事をまとめたい。
ReactドキュメントのMainConseptの部分を参考にまとめています。
Reactは、ドキュメントが日本語でも比較的読みやすいと思うので、まだ読んだことない人はぜひ読んでみてください。
※この記事では正確に意味を汲み取りたいため、英語版を参照しています。
ReactElementとは
Documentを読んでいたらReactを理解するためには、タイトルにも書いた「ReactElement」を理解することが一番なのではないかと思った。「React要素」と日本語では訳されているけど、ここでは原文のまま使っていきたい。
ReactElementとは、ドキュメントから引用すると、画面に表示したいものの説明書きのことだ。
もっと言うとJavaScriptのobjectみたいなものだ。
ReactではこのReactElementを、React.createElementメソッドを使って作成している。
createElementメソッドの引数にはtypeが入る。このtypeには、<div> や<span>などのtagの名前やReact componentを受け取り、後はオプションとして、要素の属性や子要素を入れられるみたいだ。
以下のような感じでcreateElementメソッドの引数に必要なものを入れられる。
実質的には、以下のようなオブジェクトに変更されるというわけだ。
Reactを触ったことがある勘のいい方ならもうわかったかもしれないが、引数にタグを渡したり、属性を渡したり、子要素を渡したり、これ何かに似ていないだろうか?
そうJSXだ。
実はJSXは、ReactElementを作成しているのだ。
正確に言えば、BabelというコンパイラがcreateElementメソッドを裏で呼んでいるようだ。
JSXを使えば、裏でBabelが動いてくれているので明示的にcreateElementメソッドを呼ぶ必要はない。
ここでは、JSXがReactElementを生成していることを押さえておこう。
さて、JSXがReactElementになることは分かったけれど、Webページに表示するためにはDOMに変更する必要がある。ReactElementはどうやってDOMに変換されるのだろうか?
次にその部分を見ていく。
renderメソッドにReact要素を渡す
ReactElementがどうやって変換されるか見る前に、まずは、Reactプロジェクトを作成しよう。
npx create-react-app my-app
コマンドでReactアプリを作成しよう。(nodeが入っている必要があります。)
プロジェクトを作成したら、index.js
ファイルを開こう。ちなみにReactのバージョンは18だ。
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
7行目から12行目まがズバリReactElementをDOMに変更しているところだ。
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
7行目のReactDOM.createRoot(document.getElementById('root'));
の部分でまず、ReactDOMから、createRootメソッドを呼び出している。
このメソッドの中で、document.getElementById('root')
を呼んでいるが、これはJavaScriptでよく見るやつHTMLのrootという名前のid属性を取得するメソッドだ。
このrootと書かれたid属性は、public/index.htmlファイル
の中に記載されている。
3行目で、<div id="root"></div>
を取得している。
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
ReactはSPA(シングルページアプリケーション)といって、1つのHTMLファイルだけを使用し、DOMを変更していくことでページを作成していくJavaScriptのライブラリだ。このindex.htmlで取得したdiv要素の中に、Reactの記述されたコンポーネントが表示される仕組みだ。
createRootメソッドで選択したidを取得したら、次にrenderメソッドを呼ぶ。そのメソッドの中に、ReactElementを入れることで、取得したid内でDOMが生成されるという仕組みだ。
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<App />はコンポーネントだが、後述する通り、コンポーネントもReactElementだ。
後は、<App />コンポーネントの中で、他のコンポーネントを呼んでいくことでいつものReactアプリを作成することができる。
ここでは、本当に表示されるのか、試しにrenderメソッドの中身を以下のように書き換えてみる。
const root = ReactDOM.createRoot(document.getElementById('root'));
const element = <h1>Hello, world</h1>;
root.render(
element
);
すると、ブラウザ上で表示が書き変わるのが確認できるはずだ。
renderメソッドを使うと、ReactDOMがReactElementをDOMに変換してくれる。
もし、中身に変更があった場合は以前のReactElementと変更されたReactElementを比較して、違いがあるなら差分だけ表示する仕組みになっているので、ページリロードが発生せずに画面が表示され、ユーザーにストレスをかけさせない仕組みになっている。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
上は、ver18以前のindex.js。renderメソッドにReactElementとgetElementByIdしてきたものをまとめて引数に取っている。
ここまでいったんまとめると、
- ReactElementは画面に表示したいものの説明書き。中身は実質JavaScriptのobject。
- JSXはReactElementを作る。裏でBabelがcreateElementメソッドを読んでReactElementに変換している。
- ReactElementを作成して、createRootから呼ばれるrenderメソッドに入れると、レンダリングされる。
JSXとは
JSXとはJavaScriptの構文を拡張したもので、簡単に言うと、JavaScriptでHTMLのタグみたいなものが書ける。
ReactElementの欄でも説明したが、JSXはBabelが裏でcreateElementメソッドを読んで、ReactElementに変換される。
JSXを使わないでReactを書くこともできるが、使わない理由はないと思う。
JSXの中で{}
を使うことで、その中でJavaScriptの変数や関数を展開することができる。
また、JSX自体も関数の中に使うことができる。
さらに詳しい使い方は公式を見て欲しい。
注意しなくてはならないのは、for文やif文はJSXの中で使うことはできないと言うこと。
これは自分もよくやってしまっていたので、if文やfor文を使うときは関数で定義してから、それをJSXの中で使用すればよいかも。
もっと詳しく説明すると、{}
の中ではJavaScriptの式は使えるけど、文は使えないらしい。
この式と文の違いは以下を参考にしてみてください。
Componentとは
ComponentはReactの中で一番重要な概念でこのComponentを組み合わせて画面を構成していく。
Componentには、クラスコンポーネントと関数コンポーネントの2種類があって、現在、専ら主流なのは関数コンポーネントだ。ここでは関数コンポーネントについて見ていく。
関数コンポーネントは、JavaScriptの関数定義と書き方が一緒で、引数にpropsというオブジェクト(propertiesの略)を受け取ることができる。
returnで返しているのは見てわかる通り、JSXだ。
このコンポーネントはまた頭を大文字にしてタグのように使い、変数の中に入れることができる。
コンポーネントがレンダリングされる時は、以下のような処理が行われる。
見たらわかる通り、コンポーネントもレンダリングする際に、createElementメソッドが呼ばれている。
createElementでコンポーネントが呼ばれた場合に、引数としてそこに書かれた属性がpropsとして、そのコンポーネントに渡される。propsはオブジェクトの形で渡されるので、受け取るコンポーネント側では分割代入などでも受け取ることができる。
<Welcom name="Sara" />
というコンポーネントの属性name="Sara"
が{ name: Sara }
となって、Welcomeコンポーネントのpropsに渡されるというわけだ。ここでは、props.name
として値を取り出して、returnの中に埋め込んでいる。
コンポーネントの中でJSXが使われているが、結局コンポーネントも<Welcom name="Sara" />
のようにタグとして、使えるので、コンポーネントもJSXと言っていいと思う。(ドキュメントではおそらく明記されていなかったが、そういうニュアンスで使われている)
まとめ
- ReactElementは画面に表示したいものの説明書き。中身は実質JavaScriptのobject。
- JSXはReactElementを作る。裏でBabelがcreateElementメソッドを読んでReactElementに変換している。
- ReactElementを作成して、createRootから呼ばれるrenderメソッドに入れると、レンダリングされる。
- Componentには関数コンポーネントとクラスコンポーネントの2つがあり現在の主流は関数コンポーネント。
- Componentはpropsという引数を受け取る。また、<Welcome />とタグとしても使える。
- コンポーネントも裏では、createElementメソッドが呼ばれる。その際に、属性がオブジェクトとしてpropsに渡される。
色々書いたが、大きなポイントとしては2点だと思う。
createElementメソッドが裏で呼ばれることにより、ReactElementになる。
作成したReactElementをrenderメソッドに渡すことで表示される。
この2点を押さえておけば大まかな概念は理解できると思う。
結局ドキュメントを見るのが遠そうに見えても、一番その言語やフレームワークを習得する近道になると思った。英語ができる人ならばまず間違いなく英語でドキュメントを参考にするのがよいと思う。
概念を押さえることで前よりReactが馴染みあるものになっていただければ幸いです。