はじめに
おはようございます、Tunです。
今回は、前回の続きでReactの基礎編を復習がてらに記載していきたいと思います。
JSX記法、render()関数
まず初めに抑えておきたいのはJSX記法というReactの書き方の基本となるものです。これはJavaScriptのファイルの中でHTMLのタグのような書き方ができるというものです。公式ドキュメントには、「JSXとはReact.creatElement(component, props,...children)
の糖衣構文にすぎない」と書かれています。
※糖衣構文(syntax suger)・・・難しく複雑な書き方を、簡単な書き方でも実現できる構文のこと
さっそく、例を見てみましょう。
<MyButton color = "bule" shadowSize = {2}>
Click Me
</MyButton>
これが以下のようにコンパイルされています。
React.createElement(
MyButton,
{color: 'bule', shadowSize: 2},
'Click Me'
)
Reactで開発するときは、JSX記法で記述しますが、コンパイル後の書き方も念頭に置いていた方がよさそうです。
また、JSX記法にルールがあります。以下の例を見てみましょう。
※下記の他に、idにrootを持つdivタグが記述されているindex.htmlがある前提です。
import ReactDOM from "react-dom";
const App = () => {
return (
<>
<h1>Hello!</h1>
<p>How are you?</p>
</>
);
};
const container = document.getElementById("root");
ReactDOM.render(<App />, container);
-
react-dom
からReactDOM
という名前でモジュールをimportする。 - 関数Appを定義し、アロー関数を記述する
- returnを書く
- その中に処理を記述する(HTMLのタグが今回の処理部分)
-
render()
関数を用いて、指定した要素の中のDOMにレンダリングし、そのコンポーネントへの参照を返す
ここで、returnのあとに<></>で括られていますが、これがJSX記法のルールです。この他にもdiv
やReactで準備されているFragment
でもいいのですが、不要なDOMを生成させないためにも空タグで囲むのが無難かもしれません。
また、Appを<>で括るのは、コンポーネントとして扱うためです。
~render()
関数について深堀~
公式には下記のような記述があります。
- Triggering a render
- Rendering the conponent
- Committing to the DOM
ReactDOM.render()はReactDOM(react-domモジュール)からimportすることで使用でき、render(element, container[, callback])
のように記述します。
上記は、レンダーをトリガーとして、過ぎにコンポーネントにレンダーし、最後にDOMにコミットする、というような流れです。
ですので、render()
関数の役割については、レンダリングの結果で差分があるか否かの判断をするために、互いのdifferenceを検出することだと解釈しています。
だがしかし!!!!
時代の流れというものは早いもの、この書籍を購入してから今までの間、Reactはv18にまでアプデしており、ReactDOM.render()
についてはレガシーな書き方になってしまった!
公式でも、
renderはReact18でcreateRootの置き換わりました。詳細はcreateRootを参照してください。
と言っていました...
ってことで、ReactDOM.render()
がReact18でcreateRoot().render()
に置き換わったということで、以下これで書き直して解説していきます。
まず、createRoot()
の書き方ですがcreateRoot(container[, options]);
というように記述します。渡されたcontainer
に対するReactルートを作成してそれを返します。rootのrender
を使ってDOM内部にReact要素をレンダーします。
const root = createRoot(container);
root.render(element);
これを踏まえて上記の例を書き換えてみましょう。
export const App = () => {
return (
<>
<h1>Hello!</h1>
<p>How are you?</p>
</>
);
};
import { createRoot } from "reacr-dom/client";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container); //← 増加
root.render(<App />);
いきなりApp.jsxが出てきたぞ...という方
これがReactの醍醐味と言える関数のコンポーネント化というもので、コンポーネントファイルの拡張子は.jsx
と書き、JavaScriptのファイルと見分けがつくようにしています。このApp.jsxを他のファイルでも使えるようにexport
しておきます。
次に、index.jsにApp.jsxを取り込みます、これはimport
で行います。またcreateRoot()
を使うには、react-dom
からではなく、新たなreact-dom/client
からimport
します。この際に、{ }で取り込んでいますが、これは別名ではなくReactDOMClientから提供されている関数を取り込んで名前をそのまま使いますよ、という意味です。{ }なしでは自分の好きな名前で定義して、ReactDOMClient自体を取り込みます。
ReactDOMよりも一文増えたかのように思えますが、ではcreateRootを追加うメリットはあるのかという疑問が芽生えます。
調べたところ、v18から並行処理の機能群にアクセス可能になったようです。この並行処理は、レンダリング途中でもユーザが操作でき、UXが向上するメリットがあるようです。React公式
今後、UXも重要になってきますので、開発コストを鑑みて導入を検討を加速させ、検討に検討を重ね、慎重に検討されてはいかがですか?
長くなりましたので、Part2はpropsから入りたいと思います。