はじめに
今までDjangoアプリを開発するときは基本的に生のjavascriptかjQueryを使っていたのですが、どうやら少し前から脱jQueryが叫ばれているようですし、実現したい機能を実装する際に便利そうだったのでReactを学習することにしました。
間違っていたら教えてください。(小声)
Reactについて
Reactの特徴
Reactはユーザインタフェースを構築するためのJavaScriptライブラリです。Reactの特徴は以下の3点です。
宣言的なView
Reactはデータの変更を検知し、関連するコンポーネントだけ効率的に更新・描画を行います。
コンポーネントベース
Reactは自分自身の状態を管理するカプセル化されたコンポーネントを作成します。コンポーネントはJavaScriptで書くことができるので、DOMに状態を持たせることなく様々なデータを扱うことができるようになります。
どこでも使える
Reactを使って新たな機能を実装する際に、既存のソースコードを書き換える必要はありません。また、Nodeを使ったサーバー上やモバイルアプリケーションの中でも動きます。
React要素とは?
React要素とは、下で説明しているJSXなどで構成されるJavaScriptのオブジェクトです。ブラウザのDOM要素とは異なり、低コストで生成することができます。React DOMがReact要素に合致するようにDOM要素を更新します。
例えば、HTMLファイルに以下のように記述するとします。
<div id="root"></div>
次にReactで以下のように記述していきます。この時HTMLファイルの中に記述したdivの中はReact DOMで管理されています。このdivのことをルートDOMノードと呼びます。このルートDOMノードの数に制限はありませんが、Reactだけでアプリケーションを構成している場合は通常ひとつだけ持たせるようにします。
const element = <h1>Hello World!</h1>
ReactDOM.render(element, document.getElementById('root'));
このコードはページにHello World!と見出しで表示します。
React要素はイミュータブルでなければなりません。一度要素を作成すると子要素や属性を変更することは出来ません。そこで、Reactを使ってUIを更新するためには新しい要素を作成してReact DOMに渡す必要があります。ただ、その方法は少し不便であるため、Reactには以下で紹介するステート付きコンポーネントがあり、より簡単にUIを更新することができます。
コンポーネントとは?
以下は簡単なコンポーネントです。”test”という文字を受け取り、描写しています。
returnの内部を見てください。HTMLのように書いていますが、これはJSXと呼ばれる構文です。このように、{ }で囲った部分にJavaScriptの式を入れることができます。(JSXの中ではfor文やif文などは使えません)
See the Pen KKMPpab by Ryuji Okura (@ryuji-commit) on CodePen.
このコードではExampleコンポーネントがデータを受け取り、描画しているだけですが、以下のようにコンポーネント内部で状態(state)を保持することも出来ます。その状態が変化するとrender()が再実行され、必要な箇所のみ再描画されます。
右側の入力欄に適当な文字を入力して、エンターやボタンで送信してみてください。入力した値が表示されるはずです。このコードでは、handleSubmit関数で送信された値をstateにセットしています。そうすることで状態が変化し、render()が再実行されて入力値が表示されているのです。
See the Pen React Example(State) by Ryuji Okura (@ryuji-commit) on CodePen.
handleChange関数を見てください。
this.setState({
text: e.target.value,
})
このように入力された値をstateのtextにセットし、そのtextをinputのvalueにすることで入力を反映させています。この関数が無ければ入力ができません。JSXの中でinputタグを使うときには注意してください。
次にhandleSubmit関数について説明します。この関数は入力値が送信された際に動作し、setStateを行う関数ですが、最初にe.preventDefault();と記述されています。
入力値はReactで制御しているためサーバに送信する必要はないのですが、ReactではJavaScriptとは違い、falseを返してもイベントを止めることができません。そこでpreventDefaultを呼び出し、submitイベントを止めています。
また、これらの関数をconstructor内で以下のようにbindしていますが、JavaScriptの仕様上メソッドの末尾に()をつけずに参照するために必要なことです。
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
この方法の他にクラスフィールド構文やアロー関数を使用する方法もありますが、個人的にはbindする方が好きです。(個人の感想です)
子要素の出力
コンポーネントの中にはSidebarやDialogのように事前に子要素を知らないものもあります。このようなコンポーネントでは以下のようにchildrenという特別なpropsを使い、子要素を受け取って出力することができます。
See the Pen WNxNYGP by Ryuji Okura (@ryuji-commit) on CodePen.
まとめ
Reactは上のExampleやMyNameなどの状態(state)を持つクラスコンポーネントや、状態(state)を持たず、propsを受け取って描画するだけの関数コンポーネントを組み合わせることによってUIを構築します。
仮想DOMについて
仮想DOMとは、今までブラウザが持っていたDOMツリーをJavaScriptのオブジェクトとして仮想的に表現し、差分だけリアルDOMに反映させることでレンダリングコストを下げるという技術です。
ReactではReact DOMと呼ばれるライブラリを用いて実装されています。そのため、Reactは必要な箇所のみリアルDOMの更新を行う事ができます。
JSXについて
JSXとは
Exampleクラスコンポーネントのコードを見てください。コードの下の方に以下のように書いていると思います。
const text = "Hello World";
const element = <h1>{text}</h1>
ReactDOM.render(
element,
document.getElementById('example2')
);
この<h1>{text}</h1>がJSXと呼ばれる構文です。上でも軽く触れましたが、{}の中にはあらゆるJavaScriptの式を使用することができます。例えば、関数はもちろんJSXの外でfor文やif文を使って配列を作って、その配列を呼び出したり、計算したり、stateやpropsを参照したりと様々な用途があります。ただし、JSXの中でfor文やif文を使う場合はひと工夫必要です。
JSXの中でループや条件分岐を行う方法
See the Pen VwjZrMd by Ryuji Okura (@ryuji-commit) on CodePen.
JSXでfor文やif文を使う方法の1つとして、上のように即時関数を使う方法が挙げられます。JSXの内部で即時関数を作り、その中でforを回したり、if文で分岐させたりして結果をreturnで返却させます。
また、ループさせたい場合は即時関数を作る以外にmapを使う方法もあります。例えば配列を既に持っていて、その中の値を順番に表示させたいときなどはmapを使うと便利です。
条件分岐させたい場合は、論理演算子を使う方法や三項演算子を使う方法もあります。
keyについて
このようにループなどでリストをレンダリングするときは、keyを設定することが推奨されています。例えば、上のコードでは<li key={i}>{i}</li>のように指定しています。keyにはその配列の中でユニークな値をセットする必要があります。今回の場合は添字ですね。keyを利用することで、Reactはどの要素が変更されたのかを識別できるようになります。
keyは兄弟要素の中で一意であればよく、全体の中でユニークである必要はありません。そのため、今回の例は2つともkeyに同じ値を指定しています。
JSXのその他の役割
JSXはそれ自体もJavaScriptの式のため、if文やfor文の中で使ったり、変数に代入したり、関数から返したりすることができます。さらに、JSXにはインジェクション攻撃を防ぐという役割もあります。
JSXを使う際の注意点
最後にJSXを使うときの注意点です。JSXはHTMLにとても似ていますが、実際はJavaScriptに近い構文です。そのため、React DOMはHTMLの属性(例えば”class”など)ではなく、キャメルケースの命名規則(例えば”className”など)を使用しています。
ついつい<div class=”hogehoge”>と書いてしまうので、気をつけてください。
おわりに
まだ学習している最中なので、新たなことを学び次第追記していきます。もし間違えている個所や改善点などありましたら、@Ryu_programsまで連絡いただければ幸いです。