create-react-appシリーズ
このブログポストはシリーズで作成しております。次はcreate-react-app
のシリーズリストです。
- Reactとは
- create-react-app
- create-react-appでTypeScriptを使う方法
- [TypeScript] create-react-appで絶対パスのimport
- create-react-appでstyled-componentsの使い方
- Jest
- create-react-appでreact-testing-libraryを使ってテストする
概要
このブログポストではReactが何か簡単に説明して、Reactの特徴について説明します。
Reactとは
ReactはUIジャバスクリプトライブラリ(JavaScript Library)でシングルページアプリケーション(Single Page Application)のUI(User Interface)を生成することに集中してるライブラリです。ReactはジャバスクリプトにHTMLを含めるJSX(JavaScript XML)と言う簡単な文法と一方向のデータバインティング(One-way Data Binding)を使ってます。そして、バーチャルドム(Virtual DOM)と言う概念を使ってウェブアプリケーションのパフォーマンスを最適化したライブラリです。
ReactはシングルページアプリケーションでUIを作るライブラリなので、シングルページを作成する他のフレームワークより足りないところがあります。例えば、Reactはページを遷移する機能を提供してないですので、Reactでページ遷移をするためにはreact-routerような追加的ライブラリを使う必要が有ます。
Reactの特徴
Reactはバーチャルドーム、一方向のデータバインディングなど色んな特徴があります。ここではこのような特徴を詳しく説明します。
バーチャルドーム
Reactはバーチャルドームを使ってウェブアプリケーションの性能を最大化しました。バーチャルドームを理解するためにはまず、HTMLとCSSがレンダリング(Rendering)される流れを理解する必要があります。
ウェブブラウザがネットワークを通じてHTMLを受け取ったらブラウザのレンタリングエンジンはHTMLをパーシングしてドームノード(DOM Node)で作られたツーリを作ります。また、CSSファイルとHTMLのエレメント(Element)のインラインスタイルをパーシングしてスタイル情報を持ってるスタイルツーリも生成します。
このようにレンターツーリが完成されたらブラウザはAttachmentと言うプロセスでスタイル情報を計算します。レンダーツーリで生成された全てのノードはattachと言う関数を持ってますが、このAttachmentと言うプロセスでこの関数が呼ばれます。呼ばれた関数はスタイルの情報を計算して結果をオブジェクトタイプで返すことになります。
この時の計算は全て同期的(Synchronous)で動作して、もしレンダーツーリへ新しいノードが追加されたらそのノードのattach関数が実行され、計算のプロセスを走ることになります。
レンダーツーリはAttachmentのプロセスが終わった後、レイアウトと言うプロセスが走ります。このレイアウトと言うプロセスはレンダーツーリの各ノードの座標を与えて性格的にどこにどう表示されるかを決定します。
最後にはブラウザはペインティング(Painting)と言うプロセスに移動します。このペインティングと言うプロセスでは各ノードへpaint関数を呼び出してレンダリングされた要素に色付けをします。
このよなプロセスが終わって表示されあたHTMLをジャバスクリプトを使ってドームを操作すると各ノードの座標を計算するためレイアウトのプロセスが再実行されて、その後色付けするためペインティングのプロセスが再び実行されます。このようにドームを操作するとレイアウトのプロセスが再実行されることをリフロー(Reflow)と言われ、ペインティングのプロセスが再実行されることをリペイントと呼ばれます。このようにリフローとリペイントはドームの各ノードについて演算処理を再び実行するのでこの処理が多くなるとWebサービスの性能が悪くなる問題が発生します。
Reactはこのリフローとリペイントが頻繁に実行される問題を解決するため画面に表示されたドームと同じドームをメモリ上に作ってドームを操作が発生するとメモリ上に生成したバーチャルドームで全ての演算を実行した後、実際のドームを更新することでリフローとリペイントの演算を最小化しました。
例えば、ユーザがTodoリストアプリを使う場合、何もないリストへTodoを一つ追加するプロセスを考えてみましょう。Todoを入力して追加ボタンを押すと何もないリストへ一つTodoが表示され、全てのTodoのカウントが表示されます。この時、バーチャルドームがない場合は、Todoを表示するためリフローとリペイントが一回発生して、全てのTodoのカウントを表示する時リフローとリペイントが再び発生します。
しかし、Reactではこのプロセスを全てバーチャルドームから実行します。したがって、ユーザがTodoを入力して追加ボタンを押すと、Todoの表示、全てのTodoのカウントを表示するためバーチャルドームで計算した後、計算結果をブラウザに渡すのでリフローとリペイントを一回だけ発生します。
このようにReactはバーチャルドームを使ってドームがよく更新されるシングルページアプリケーションのリフろーとリペイント最小化をして性能を最適化しました。
一方向データバインティング
一方向データバインティングを説明する前に双方向データバインディングについてちょっと説明します。双方向データバインディングはUIのデータが変更されることを監視しるWatcherとジャバスクリプトデータの変更を監視するWatcherがUIとジャバスクリプトのデータを自動で同期化してくれる方式を言います。この方式を使うとプログラマはジャバスクリプト内のデータ変更とUIのデータ変更に関するデータ同期化を気にしなくてプログラムを作成することができます。
しかし、一つのデータを同期化するため二つのWatcherが使用され、データが多くなるとこのデータの同期化のためたくさんのWatcherが生成されて、逆に性能が悪くなる問題が発生します。
この問題のせいで、Reactは他のフレームワークとは違って一方向データバインティングを使ってます。
一方向データバインティングは一つのWatcherがジャバスクリプトのデータの更新を検出してユーザのUIデータを更新します。ユーザがUIを使ってジャバスクリプトのデータを更新する時は、イベントを使って更新します。このように一方向データバインティングは一つのWatcherを使うので双方向データバインティングが持ってる性能的問題を解決し、もっと簡単にデータを追跡できるようにします。
JSX
ReactではJSXと言う独特の文法を持っています。JSXはジャバスクリプトとHTMLを同時に使って、HTMLでジャバスクリプトの変数を直接使える一種のテンプレート言語(Template language)です。
const App = () => {
const hello = 'Hello world!';
return <div>{hello}</div>;
};
Reactは上のようにジャバスクリプトでHTMLタグを使うことができるし、ジャバスクリプト変数をHTMLタグで直接呼び出すことができます。ジャバスクリプトの開発者ではこのJSXがすごく変な文法ですが、他の言語をみてみると、もっと簡単に理解できます。
例えばJavaのjspでは次のようにHTMLタグ中でJavaの変数を使えることができます。
<div><%= hello %></div>
もちろんReactのJSX文法とは少し違いますが、このようにJSXをジャバスクリプトの文法ではなく一種のテンプレート文法と覚えるともっと簡単に理解できます。
宣言型プログラミング
プログラミングでは命令型プログラミングと宣言型プログラミングで区分することができます。命令型プログラミングはプログラミングをする時どのように(How)
へ集中することで、宣言型プログラミングは何(What)
へ集中してプログラミングをすることです。
例えば、タクシに乗って家に帰る時を命令型プログラミングで説明すると”最初の交差点で右に曲がって次の慎吾まで直進して次の慎吾で左に曲がると私のいえです。”ようにどのように
家に帰ることに集中して説明します。しかし、宣言型プログラミングはこれを説明する時、”私の家はXXX番地です。”とように家という何
へ集中して説明します。
実際ソースコードをみて理解してみましょう。
- 命令型プログラミング
const double = (arr) => {
let results = [];
for (let i = 0; i < arr.length; i ++) {
results.push(arra[i] * 2);
}
return results;
}
- 宣言型プログラミング
const double = (arr) => {
return arr.map((elem) => elem * 2);
}
上の二つの関数は同じ動きをする関数で、与えた配列の値を二倍する動作をします。最初の命令型プログラミングでは与えた配列の値を二倍にするため、For文を使ってi変数と配列のサイズを使って配列の値を一つずつ取ってきて二倍にした後、resultと言う新しい配列へ入れって、結果として返します。このように命令型プログラミングはプロセスを中心にプログラミングをします。
二つ目の関数は宣言型プログラミングでmap関数を使って与えた配列の値を二倍にして返してます。mapがどう動作するかは気にしなくて結果である配列を二倍にすることに集中してプログラミングをしています。
このようにライブラリやフレームワークなどを使って非宣言型的な部分をカプセル化することで命令型プログラミング言語で宣言型プログラミングをすることができます。Reactでは特にJSXが使えるので宣言型プログラミングをもっと活用してます。
- 命令型プログラミング
<ul id=”list”></ul>
<script>
var arr = [1, 2, 3, 4, 5]
var elem = document.querySelector("#list");
for(var i = 0; i < arr.length; i ++) {
var child = document.createElement("li");
child.innerHTML = arr[i];
elem.appendChild(child);
}
</script>
上の例題はジャバスクリプトを使ってHTMLで新しいリストアイテムを追加するコードです。上のコードは命令型プログラミングでリストを新しいリストを表示するulタグを生成してジャバスクリプトのquerySelectorを使って表示する位置を取ってきて、for文を使って一つずつリストへアイテムを追加してます。
- JSXを使った宣言型プログラミング
const arr = [1, 2, 3, 4, 5];
return (
<ul>
{arr.map((elem) => (
<li>{elem}</li>
))}
</ul>
);
ReactのJSX文法を使うと上のようにHTML中でもmap関数を使ってリストアイテムを追加することができます。このようにJSXを使うとジャバスクリプトだけではなくHTMLでも宣言型プログラミングができます。
コンポーネントベース
Reactでウェブサービスを開発する時、コンポーネント
と言う小さく孤立されたコードを使ってUIを構成します。
const Title = () => {
return <h1>Hello world</h1>;
};
const Button = () => {
return <button>This is a Button</button>;
};
const App = () => {
return (
<div>
<Title />
<Button />
</div>
);
};
このように小さくて孤立されたコンポーネントは再利用ができルシ、このように再利用することによって開発の生産性が上がります。また、このように小さくて孤立されたコンポーネントはテストも簡単にできるのでメインテナンスにも役に立てます。
完了
今回のブログポストではReactとは何か、Reactの特徴は何かをみてみました。今後続くブログポストではこのReactを使う方法について説明します。
私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!
アプリ広報
Deku
が開発したアプリを使ってみてください。Deku
が開発したアプリはFlutterで開発されています。興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。