こんにちは、アイダです。 今回は、数あるJavaSciptのライブラリ・フレームワークの中でも人気を誇る、Reactについてお話します。 食欲の秋が年中続いているNさんが、初心者向けにReactの要点をかみ砕いて説明してくれました。それではNさんどうぞ。
はじめに
Reactを学習するにあたって必ず耳にする「コンポーネント指向」、「宣言的View」、「仮想DOM」などの言葉の数々…。難しいと感じたことはありませんか?
私は入社後4年間バックエンド開発に携わってきて、今年からフロントエンド開発にチャレンジすることになりました。
早速Reactの勉強を始めたのですが、よく出てくるキーワードが一度聞いてもぱっと分からないものだらけで、挫折しそうになりました。
この記事では、私のように挫折しそうな人や、これから学習を始めようとしている人向けに、Reactを学習するうえで避けては通れないキーワードを頑張ってかみ砕いて説明します。
この記事では下記のキーワードを説明していきます。この言葉の羅列を見ただけでもつらい胸がドキドキしてきますね!盛りだくさんなので、分かるものは飛ばして読んでいただいて大丈夫です!
- コンポーネント指向
- JSX
- 宣言的View
- 仮想DOM
- フック
- Next.js
- TypeScript
Reactの主要なキーワード
コンポーネント指向
画面を構成する部品(=コンポーネント。例えばボタンや記事、ヘッダーなど)に分けて開発し、それを組み合わせてWEBアプリケーションを開発する考え方のことです。
Reactではコンポーネントを作成し、それを組み合わせることで複雑なユーザーインターフェースを作成します。
コンポーネント指向の開発は下記のメリットがあります。
- コンポーネントは再利用できるので、開発を効率化できる。
- 仕様変更された場合に、コンポーネントのコード修正のみで済む。
Reactのコンポーネントの実体はJavaScriptの関数もしくはクラスです。
具体例として、コンポーネントを使ってページ上に「Reactの勉強は楽しい!」と表示するコードを書いてみます(デモを通して自らに暗示をかけていくスタイル)。
開発環境は新しい React アプリを作る – Reactの手順に従って作成することができます。Create React Appで作成した環境で動作確認を行う場合は、以下のJavaScriptをindex.jsに記載してください。
まず初めに、「React」の部分を引数(props)のnameとして受け取り、「{props.name}の勉強は楽しい!」と表示するコンポーネントを作成します。
// コンポーネントを関数で実装する場合 function TestComponent(props) { return <h1>{props.name}の勉強は楽しい!</h1>; } // コンポーネントをクラスで実装する場合 // class TestComponent extends React.Component { // render() { // return <h1>{this.props.name}の勉強は楽しい!</h1>; // } // }
戻り値のHTMLに似た記述(<h1>{props.name}の勉強は楽しい!</h1>
)はJSXというJavaScriptの拡張構文です(後ほど説明します)。
コンポーネントの戻り値はReact要素と呼ばれるオブジェクトで、要素のレンダー – Reactに記載の通り、「画面上に表示したいものの説明書き」です。
次に、HTMLファイルにReact用の最上位のDOMノード(=ルートDOMノード)を定義します。 ルートDOMノードがReact要素のレンダー先になります。
<!-- 他のHTMLの記述 --> <div id="root"></div> <!-- 他のHTMLの記述 -->
最後に、ReactDOM.createRoot()
にルートのDOM 要素を渡し、root.render()
に引数nameにReactを指定したコンポーネント(<TestComponent name="React" />
)を渡します。コード全体は下記になります。
import ReactDOM from "react-dom/client"; function TestComponent(props) { return <h1>{props.name}の勉強は楽しい!</h1>; } const root = ReactDOM.createRoot(document.getElementById('root')); const element = <TestComponent name="React" />; root.render(element);
画面に下記のように表示されればOKです。React学習のやる気がみなぎる素敵なUIの完成です。
コンポーネントは下記例のように再利用が可能です。下記例ではコンポーネントごとに引数の値を変えてみました。
import ReactDOM from "react-dom/client"; function TestComponent(props) { return <h1>{props.name}の勉強は楽しい!</h1>; } const root = ReactDOM.createRoot(document.getElementById("root")); const element = ( <div> <TestComponent name="フロントエンド" /> <TestComponent name="React" /> <TestComponent name="プログラミング" /> </div> ); root.render(element);
するとあら不思議、自分にさらに暗示をかけることのできる素敵なUIが完成しました。
JSX
下記のような、HTMLに似た記述を書けるJavaScriptの拡張構文のことです。Reactコンポーネントを定義する際に使います。
const element = (
<div>
<h1>React</h1>
<h2>Reactの学習を始めよう!</h2>
</div>
);
ReactではJSXの利用は任意ですが、JSXを利用するメリットとしては下記が挙げられます。
- コードが簡潔になる
- 最終的なDOM構造が分かりやすい(HTMLに似た構造で、階層構造になっているため)
上記のコードをJSXなしで書くと下記のようになります。
const element = React.createElement( "div", null, React.createElement("h1", null, "React"), React.createElement("h2", null, "Reactの学習を始めよう!") );
宣言的View
宣言的と命令的について
宣言的(declarative)とは、プログラムに何かを実現してほしいときに、実現したいもの(what)を伝えることを言います。宣言的とよく比較される言葉が、命令的(imperative)です。こちらは実現する方法(How)を伝えます。
例えば、スパイスカレーが無性に食べたいけれど、自分で作る気力はなく、あわよくば誰かに作ってほしいとします。
もし宣言的にお願いするなら、「スパイスカレーを作って!」と伝えればOKです。
一方で、命令的にお願いするなら、「材料は近所のスーパーで買ってね。材料を切って炒めて水を入れて(かくかくしかじか)お皿に盛ってね」と、細かい手順まで指示します。
宣言的Viewとは
WEBアプリケーションで保持するデータ(以下、状態と呼ぶ)と、そのデータを反映するUIの最終形を定義しておけば、状態が更新された際にReactが裏側でDOM操作をしてくれることを指します。
「裏側で」というのがReactの良いところです。Reactを使わずに純粋なJavaScriptで実装する場合、命令的にDOMの操作を記述する必要があります。
具体例として、チェックボックスにチェック付け外しするとラベルの内容が変わるページを作成してみます。
まずはReactで作成してみます。
import React, { useState } from "react"; import ReactDOM from "react-dom/client"; const CHECKBOX_ID = "test-checkbox"; const BEFORE_LABEL_TEXT = "チェックを付けてね"; const AFTER_LABEL_TEXT = "チェックを外してね"; function App() { /* WEBアプリケーションで保持する状態の定義 */ // チェックボックスのチェック状態 const [isChecked, setIsChecked] = useState(false); // チェックボックスラベルのテキスト const labelText = isChecked ? AFTER_LABEL_TEXT : BEFORE_LABEL_TEXT; // チェック状態変更時に実行される関数の設定 // ここでチェック状態が更新される function changeHandler() { setIsChecked((prevState) => !prevState); } /* データを反映したいUIの定義 */ return ( <div> <input checked={isChecked} type="checkbox" id={CHECKBOX_ID} onChange={changeHandler} /> <label htmlFor={CHECKBOX_ID}>{labelText}</label> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />);
この例では、チェックボックスのチェック状態により、最終的なUIが変わります。チェック状態を更新する関数は定義していますが、チェック状態が変わった時に<label>
タグのテキストを書き換える記述はしていないのがミソです。
チェック状態が変わると、Reactが裏側で<label>
タグのテキストの書き換えを行ってくれます。
これをReactを利用せずに純粋なJavaScriptで書くと以下のようになります。
チェック状態が変わった時に<label>
タグのテキストの書き換えを行っています。Reactと異なり、直接的なDOM操作を行っているのが特徴です。
const CHECKBOX_ID = "test-checkbox"; const BEFORE_LABEL_TEXT = "チェックを付けてね"; const AFTER_LABEL_TEXT = "チェックを外してね"; /* チェックボックスを作成する */ const checkboxElement = document.createElement("input"); checkboxElement.type = "checkbox"; checkboxElement.id = CHECKBOX_ID; /* チェックボックスラベルを作成する */ const labelElement = document.createElement("label"); const labelTextNode = document.createTextNode(BEFORE_LABEL_TEXT); labelElement.htmlFor = CHECKBOX_ID; labelElement.append(labelTextNode); /* ID「root」を持つdivタグにチェックボックスとラベルを紐づける */ const appContainerEl = document.getElementById("root"); appContainerEl.append(checkboxElement); appContainerEl.append(labelElement); /* チェックボックスのイベントリスナーを作成 */ checkboxElement.addEventListener("change", checkboxHandler); function checkboxHandler(event) { // チェックが入ったら、ラベルのテキストをチェック後のものに変更する // チェックが外されたら、ラベルのテキストをチェック前のものに変更する if (event.target.checked) { labelTextNode.textContent = AFTER_LABEL_TEXT; } else { labelTextNode.textContent = BEFORE_LABEL_TEXT; } }
仮想DOM
Reactでは、状態が更新された際に、まずインメモリに仮のDOMを作成して、更新前のDOMと比較し、差分がある場合にのみ実際のDOMを更新します。この仕組みを仮想DOMと呼びます。
仮想DOMの仕組みにより、Reactの宣言的Viewが実現されています。 また、差分がある場合のみ実際のDOMを更新するので、効率的なUIの更新にも一役買っています。
フック
状態管理などのReactの機能をJavaScriptのクラスなしで利用できるようにしたものです。
フックが導入されるまでは、状態管理はクラスでのみ利用可能だったため、コンポーネントはクラスで書くのが一般的でした。
しかし、JavaScriptのクラス型の学習コストの高さなどを理由に、React 16.8からフックが新機能として追加され、関数コンポーネントでも状態管理が可能になりました。
では、フックが導入されている現在、コンポーネントは関数とクラスどちらで書けばよいのでしょうか?公式ドキュメント(フックに関するよくある質問 – React)に下記記載があり、フックを利用した関数コンポーネントの利用が推奨されていることが分かります。
長期的には、フックが React のコンポーネントを書く際の第一選択となることを期待しています。
Next.js
Reactをベースに開発されたフロントエンドフレームワークです。
アプリケーションに開発に必要な機能があらかじめ組み込まれた状態で開発を始めることができます。
Next.jsでサポートされている機能には、サーバーサイドレンダリングや、ルーティングのフォルダ階層による管理などがあります。(Reactの場合、ルーティングはReact Routerというライブラリでも可能ですが、コンポーネントにパスを紐づける必要があります(コード分割 – React))
似た言葉にNuxt.jsがありますが、Nuxt.jsはVue.js(Reactと同じく人気のあるWEBアプリケーションフレームワーク)をベースとしたJavaScriptフレームワークです。
TypeScript
JavaSciptを拡張して開発された、静的型付けができるプログラミング言語です。
コードの実行前に型不整合等のエラーやバグ検知ができることから、大規模なプロジェクトでは開発効率向上のためTypeScriptの利用が推奨されています(静的型チェック – React)。
おわりに
Reactの勉強を始めて間もないなか、このブログでこれだけの量のキーワードを説明するのはなかなか大変でした…。
しかし、説明しようと思って言語化しようとするなかで、自分の理解が足りない部分が明確になって、とても良い勉強になりました!
フロントエンドまわりの技術は移り変わりが激しく、勉強を続けるのが大変ですが、この記事がReactの要点をぱっと掴むきっかけになれば嬉しいです。