Reactとは
Reactとは。UI構築に特化したJavaScriptライブラリです。
Reactの特徴
コンポーネント指向
コンポーネント指向とは、部品単位に小さく分けて開発を進める考え方です。
ReactにおけるコンポーネントとはUIを構成する部品であり、ページを構成するUI要素を再利用できる単位で切り出したJSXを返すJavaScriptの関数。
仮想DOM(Document Object Model)による高速レダリング
ReactはDOMを仮に構築する仕組みを備えており、仮想DOMを構築してからリアルDOMを構築する
ReactにおけるDOM構築は変更差分のみを更新するために処理のスピードが速く、Webページを高速で切り替えることができる
リアルDOM
画面を表示するために解釈されたHTML、CSS、JavaScriptによって構築されたDOM(ツリー)です
DOMはブラウザ上でWebページを描画するために構築される
状況が変わるなどの変化があった場合、全てのDOMを再構築し再描画を行なってブラウザ表示を変化させます
仮想DOM
仮想DOMはリアルDOMに比べ、ページの表示の高速化を実現する
変更前と変更後の仮想DOMを比較し、変化があった部分だけを見つけ変更差分のみリアルDOMを再構築する
その後、再描画を行いブラウザを変化させる
Reactの用語
ReactDOM.render
コンポーネントをDOM変換して出力してくれるのがReactDOM.render()であり、Reactコンポーネントの内容をブラウザに描画させるためのものです
import ReactDOM from 'react-dom'
// Funcコンポーネント
const Func() => {
return <h1>Hello World</h1>
}
// ReactDOM.render()で <div id="root"></div> に <Func /> を割り当てる
// 第2引数で指定したdocument.getElementById("root")に対して、
// 第1引数で指定した<Func />コンポーネントを割り当てる
// ReactDOM.render()がコンポーネントをDOMに変換し、ターゲットであるHTMLの
// <div id ="root"></div> にレンダリングする
ReactDOM.render(<Func />, document.getElementById("root"));
React <Func />
→ ReactDOM.render → HTML <div id ="root"></div>
→ Hello World
JSX
JSX(JavaScript XML)はReact要素を生成するJavaScriptの拡張構文であり、ほとんどのHTMLタグが利用可能です。JavaScriptに直接、HTML/XMLと似たような記述をすることができます。
// JSX構文を使用した例
const App = () => {
return (
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
);
};
JSX構文を使った場合と使わなかった場合では、コードの可読性に大きな違いが出ます。
また、JSXはHTMLタグや属性をそのまま使うことができますが、HTMLのclass
はJavaScriptでは予約後に当たるため、代わりにclassName
を利用します。また、JSXでは複数の要素を並列で配置できないため、必ず以下のように最上位に1つの要素を配置するというルールがあります。
// NG例(要素を並列に配列)
const AppNG = () => {
return (
<p>aaa</p>
<p>bbb</p>
<p>ccc</p>
);
}
// OK例(最上位に要素を配置)
const AppOK = () => {
return (
<div>
<p>aaa</p>
<p>bbb</p>
<p>ccc</p>
</div>
);
}
// 要素を増やしたくない場合、<> を使用する
const AppOK2 = () => {
return (
<>
<p>aaa</p>
<p>bbb</p>
<p>ccc</p>
</>
);
}
また、JSXではimg
タグやbr
タグの要素末に/
を入れないとエラーになります
<img src="xxx.png" alt="ロゴ画像" />
<br />
style属性
JSXでは直接style
属性を使用することができません
// NG例
const AppNG = () => {
return (
<h1 style="font-size: 16px; color: white">Hello World</h1>
);
}
// OK例
// 外側の{}はReact記法で、内側にJavaScriptを記述することができます
// 内側の{}は一般的なJavaScriptのオブジェクト定義になります
const AppOK = () => {
return (
<h1 style={{fontSize: 16px, color: 'white'}}>Hello World</h1>
);
}
// OK例2
// jsxStyleをオブジェクトで宣言
// 数値プロパティに単位をつけない場合、自動的にpxが設定される。今回の場合16pxとなる
// px以外をつけたい場合、単位を指定する
const jsxStyle = {
fontSize = 16,
color:'red'
}
const App = () => {
return <h1 style={jsxStyle}>Hello World</h1>
Reactでは構造とスタイルを分離することが推奨されています
なので、style属性の使用はあまり推奨されていません
value属性
フォームに入力された値がstate(状態)として保持され、setState()
関数でのみ更新されるReactコンポーネントのことを制御されたコンポーネントといいます
一方、フォームに入力された値のstate(状態)が制御されていない非制御コンポーネントの場合、input
要素などのvalue
属性でフォームの初期値を設定してしまうと、後から値を変更することができません
非制御コンポーネントでは、Reactに初期値を設定したいが、更新内容には関与させたくない場合、value
属性の代わりにdefaultValue
属性を指定します
// Hello Worldが最初にUIに表示される値
const App = () => {
return <input type="text" defaultValue="Hello World" />
}
checked属性
フォーム要素の入力値の状態が制御されていない非制御コンポーネントの場合、ラジオボタンやチェックボックスであってもchecked
を付与すると、後からchecked
の変更ができなくなってしまいます
そこで、checked
の代わりにdefaultChecked
属性を使用します。
const App = () => {
return (
<>
<input type="radio" name="radio1" value="radio1" defaultChecked={true} />
<input type="radio" name="raido2" value="radio2" />
</>
}
props
Reactコンポーネントが管理するデータにはprops
とstate
があり、これらの値によってUIの情報や状態を管理しています
props
とは親コンポーネントから子コンポーネントに渡される属性値(データ)のことで、子コンポーネントでは引数で受け取った値や関数を利用することができます
propsで受け取る
// 子コンポーネント
// 子コンポーネントであるChildコンポーネントで親コンポーネントから渡されたnameをpropsとして受け取る
const Child = (props) => {
return <p> Hello {props.name} </p>;
};
// 次のように記述することも可能
const Child = ({name}) => {
return <p> Hello {name} </p>;
};
propsで渡す
// 親コンポーネント
// 子コンポーネントであるChildコンポーネントへpropsを渡す側の親コンポーネントをParentコンポーネントとする
const Parent = () => {
return <Chlid name = "Sato" />;
}
まとめると以下のようになります
// 子コンポーネント
// 親コンポーネントからpropsとしてnameを受け取る
const Child = (props) => {
return <p> Hello {props.name} </p>;
}
// 親コンポーネント
// 子コンポーネントへpropsとしてnameを渡す
const Parent = () => {
return <Child name = "Sato" />;
}
// ReactDOM.render()で、<div id="root"></div>に<Parent />a を割り当てる
ReactDOM.render(<Parent />, document.getElementById("root"));
returnの省略
アロー関数では複数行の関数を書く場合は{}を利用し、その結果を得るためにはreturnが必要
// アロー関数が1行であるため、returnを省略することが可能
const Hello = () => <p>Hello World</p>
Hello();
state
state
とはコンポーネントが内部で保持する状態のことで、画面上に表示されるデータなど、アプリケーションが保持している状態を指す
state
が更新されると、stateを管理するコンポーネントが再描画されることにより、画面上のUIや挙動が変わります
useState
関数コンポーネントではstate
を管理するのに、フックのuseState()
を利用する
// 状態の定義
const [状態変数, 状態を変更するための関数] = useState(状態の初期値);
例として、LikeButton
(いいねボタン)のstate管理を考えます
// liked:stateの状態を持たせている変数/現在の値
// setLiked:likedの状態を変更する関数
// false:likedの初期状態、初期値の「いいね」されていない状態をfalseとする
const [liked, setLiked] = useState(false);
状態を変更するための関数の命名は一般的に、set + 状態変数 にするようです。
今回の場合、状態変数がliked
であるため、状態を変更するための関数はsetLiked
になる
// 関数コンポーネント内でstateを使えるようにするため、React import時に useStateを読み込む
import React, {useState} from 'react';
cont LikeButton = () => {
// 関数コンポーネント内の一番上の位置で状態管理の宣言を行う
const [liked, setLiked] = useState(false)
// ボタンが押される度に、「いいね済み(true)」と「いいね前(false)」を変更する
const toggleLiked = () => setLiked(!liked);
// ボタンを定義
return (
<button onClick={toggleLiked}>{liked? "いいね済み" : "いいね前"}</button>
);
}
レンダリング
Reactにおけるレンダリングとは現在のprops
とstate
をもとにコンポーネントに対してそれらがどのように画面に表示されるのか、変更前と変更後の仮想DOMを構築して変更差分を検出することで、実際にDOMに変更を加える必要があるかどうかを知るためのプロセスです。
レダリングは以下のような変化が発生したレンダリングで実行される
- コンポーネントの初回レンダリングとき
- コンポーネント内の状態(state)が変化したとき
- 親コンポーネントがレンダリングされたとき
- カスタムフックからコンポーネントが受け取っている変数が変化したとき
再描画
Reactコンポーネントでは、初回読み込み時に最初の描画が行われます
初回読み込み以外、2回目以降の描画のことを再描画といい、レンダリングによって変更差分が見つかった場合、構築されたリアルDOMをブラウザに反映する
Reactがコンポーネントを再レンダリングしても変更差分がない場合、再描画は行われない
メモ化
メモ化とは同じ結果を返す処理に関して、初回のみ処理を実行記録しておき、値が必要となった2回目以降は前回の処理結果を計算することなく呼び出し、値を得られるようにする
都度計算する必要がなくなるため、パフォーマンスの最適化が期待できる
Context機能
Contextとは、子コンポーネントが親からprops
を渡されていなくても、Context
に収容されているデータへよりシンプルアクセスできる機能
親から子、子から孫のようにバケツリレー形式でpropsを渡さなくても、親から孫へ直接値を渡すことができます