Reactとは
Reactは、ユーザーインターフェースを構築するためのJavaScriptライブラリです
基本
Reactは、ユーザーインターフェイスを構築するためのJavaScriptライブラリです。Facebookが開発し、ウェブアプリケーションやモバイルアプリケーションのフロントエンド開発に広く使用されています。Reactの主な特徴は以下の通りです:
-
コンポーネントベース: Reactは、UIを独立した再利用可能なパーツ(コンポーネント)に分割し、各コンポーネントが自身の状態を管理できるようにします。これにより、大規模なアプリケーションも簡単に管理しやすくなります。
-
データフローの一方通行: Reactではデータが一方向に流れるという設計が採用されており、コンポーネント間のデータの流れを容易に追跡でき、アプリケーションの動作が予測しやすくなります。
-
宣言的ビュー: Reactを使用すると、どのような状態においてもUIがどのように見えるべきかを宣言し、データが変更されたときにReactが効率的にビューを更新します。
-
学習曲線: Reactの基本的な概念は比較的学びやすく、小規模なプロジェクトからでも始めやすいですが、アプリケーションが大規模になるにつれて、より高度な概念やパターンを理解する必要があります。
-
強力なエコシステム: Reactには豊富なライブラリやツールがあり、ルーティングや状態管理、APIとの連携など、開発のあらゆる側面をサポートしています。
これらの特性により、Reactはフロントエンド開発の分野で非常に人気があり、多くの企業がプロダクション環境で利用しています。
ReactDOM.renderを定義する
ReactDOM.renderは、Reactのもっとも根幹をなすもので、作成したコンポーネントを実際のHTMLの中のどの場所を起点に描画するかを指定するために利用します。
通常、アプリケーションの中で一度だけ記述します。
ReactDOM.renderで指定された起点をコンテナと呼び、Reactはこのコンテナの中にコンポーネントを展開します。
コンポーネントを定義する
「Hello world」をh1タグで囲ったコンポーネントを作成するには、次のように記述します
<h1>Hello world</h1>
コンポーネントは次の3つの部分で構成されいます。
- テンプレート
描画されるHTMLテンプレート - ロジック
描画や状態を扱うためのロジック - 状態(State)
コンポーネント内部で保持している値
コンテナを指定する
ReactDOM.renderでコンポーネントを描画するためコンテナを指定します。
Id属性でDOMの参照を取得するためにはgetElementByIdを利用します。
Reactを使ってブラウザのDOMに「Hello world」というテキストを持つh1要素を表示する
ReactDOM.render(
<h1>Hello world</h1>,
document.getElementById("root")
);
このコードが実行されると、< h1>Hello world< /h1> というReact要素がidが"root"のHTML要素内に描画されます。これにより、ウェブページ上に"Hello world"と表示されるh1タグが現れます。このプロセスは、ReactがDOMを効率的に更新できるよう管理し、アプリケーションのパフォーマンスを最適化するのに役立ちます。
コンポーネントをJSXで定義する
「Hello world」をh1タグで囲ったコンポーネントを作成するには、次のように記述します。
const app = <h1>Hello world</h1>
JSXはJavaScriptのオブジェクトとして扱えるため、上のように変数に格納することができます。
JSXの構文はHTMLと非常に良く似ていて次のように定義します。
<開始タグ>ここにボディ終了タグ>
ボディがない場合は、次のように1行で短縮して書くこともできます。その際は終了タグを表す/を忘れないようにしてください。
<開始タグ />
const app = <h1>Hello world</h1>;
// rootの場所に描画する
ReactDOM.render(
app,
document.getElementById("root")
);
実行時には、app変数に割り当てられた< h1>Hello world< /h1>のReact要素が、idが"root"のHTML要素内に描画されます。このように、変数を使用してReact要素を管理する方法は、複雑なアプリケーションにおいて特に役立ちます。変数に割り当てることで、その要素を繰り返し使用したり、条件に応じて異なる要素をレンダリングするロジックを簡単に追加できます。
JSXでJavaScriptの構文を使う
JSXは{と}で囲うことでJavaScriptの構文を埋め込むことができます。
そのため、「1 + 1」の結果をJSXに埋め込むためには次のように{}で数式を囲います。
<h1>1 + 1 = {1 + 1}</h1>
関数greetingをJSXの中で呼び出すためには、次のように記述します。
<h1>Hello {greeting()}</h1>
他にも、オブジェクトのプロパティを参照したり、三項演算子などを組み込むことも可能です。
<h1>Hello {user.name}</h1>
<h1>Hello {isGuest() ? "ゲスト": user.name}</h1>
JSXにAttributeを設定する
JSXへは、HTMLと同様に任意の属性(Attribute)を定義することができます。
このような属性を使ってコンポーネントに引数を渡す方法は、非常に良く使われるテクニックです。
name属性を定義する
<h1 name="everyone">Hello world</h1>
ここでは属性値をクォート記号("か')で囲っているため、この値は文字列型として取り扱われます。
数値型や真偽型として属性値を渡す
<!-- これは文字の「1」 -->
<div size="1" />
<!-- これは数字の「1」 -->
<div size={1} />
数値型や真偽型として属性値を渡す場合は、{}で囲って渡す必要があります。
関数greetingを呼び出し
<h1 name={greeting()}>Hello world</h1>
属性値をクォート記号("か')で囲った場合は、文字列として処理され、{}で囲った場合はJavaScript構文として扱われるということです。
文字列
<!-- これは、「{greeting()」という文字列 -->
<h1 name="{greeting()}">Hello world</h1>
"と{}が逆転した場合は、文字列として扱われます。
オブジェクトを渡す
<h1 name={{ name: "everyone" }}>Hello world</h1>
{}で囲った中は、JavaScript構文として処理されるため、オブジェクトを渡すためには次のように{}を二重にします。
コンポーネントとProps
シンプルなコンポーネント
Reactでもっともシンプルにコンポーネントを作成する方法は、function句を利用する方法です。
functionでコンポーネントを定義し、その戻り値でコンポーネントを返します。
function Greeting() {
return <h1>Hello world</h1>;
}
コンポーネントを利用するためには次のようなJSXタグとして利用します。
<Greeting />
React.Componentを利用したコンポーネント
ES6のclass構文を使ってReactのコンポーネントを定義するためには、次のように記述します。
class Greeting extends React.Component {
}
render関数を定義することで、コンポーネントのテンプレートを描画することができます。
render() {
return <h1>Hello world</h1>;
}
render関数は、React.Componentでコンポーネントを作成する場合、必ず定義しなければならない関数です。
render関数で何も描画するものが無い場合は、nullやfalseを返してください。
これは、次のような条件に応じてコンポーネントを描画するために良く使うテクミックです。
render () {
// まだ値の準備ができてない場合は描画しない
if (!someValue) {
return null;
}
return <h1>Hello {someValue}</h1>;
}
コンポーネントをネストさせる
コンポーネントが複数行になる場合は、次のように()で囲ってひとまとまりとすることができます。
const app = (
<div>
<Greeting />
<Greeting />
<Greeting />
</div>
);
実際のところ()は必須ではありませんが、次のようにインデントを揃える時に苦労することがあるため、ここでは()を付けるようにしています。
const app = <div>
<Greeting />
<Greeting />
<Greeting />
</div>;
注意するべきこととして、Reactコンポーネントは次のような複数のコンポーネントを返すことができません。
const app = (
<Greeting />
<Greeting />
<Greeting />
);
複数のコンポーネントを返す場合は、< div>タグなどで囲う必要があります。
Propsでコンポーネントに引数を渡す
コンポーネントにname属性を渡すためには、次のようにコンポーネントにAttributeを追加します。
<Greeting name="everyone" />
この例は、Stateless function componentであるため、コンポーネントに渡された属性値はfunctionの第一引数に格納されています。
慣例でpropsという名前で受け取るようにしています。
コンポーネント内でname属性を利用するためには、次のようにprops引数のnameプロパティを参照します。
function Greeting(props) {
return <h1>Hello {props.name}</h1>;
}
React.Componentの場合はthis.propsを利用します。
render () {
return <h1>Hello {this.props.name}</h1>;
}
コンポーネントをネストさせるためには、HTMLのタグと同様にJSXタグをネストさせます。
<Border>
<Greeting name="everyone" />
</Border>
JSXのタグボディはpropsオブジェクトのchildrenという特別なプロパティに格納されます。これを使うことでネストしたコンポーネントを描画することが可能です。
function Border(props) {
// Borderコンポーネントのタグボディを子コンポーネントとして描画する
return <div className="bordered">{props.children}</div>;
}
props.childrenには< Greeting name="everyone" />がそのまま格納されています。
Propsの型をチェックする
コンポーネントのpropsに型チェックを追加するためには、コンポーネントのpropTypesプロパティに、チェックするプロパティのキーとルールを設定します。
ルールは、PropTypesを利用して定義します。
Greeting.propTypes = {
name: PropTypes.string
};
チェックでエラーとなった場合は、次のようなエラーメッセージが表示されます。
コンポーネントのイベントハンドリング
コンポーネントでのイベントハンドリングの方法は、HTMLと非常に似ており、コンポーネントにイベント名とハンドラを追加します。
<h1 onClick={handleClick}>Hello {props.name}</h1>
HTMLと異なる点としては、イベント名がcamelCaseを使っていることです。
HTMLの場合のイベント名はonclickです。
イベントハンドラをPropsで渡す
コンポーネントにAttributeを追加します。
<Greeting name="everyone" onClick={handleClick} />
onClick属性はpropsに一度格納されるため、コンポーネント内で利用するためには、props.onClickの参照を利用します。
<h1 onClick={props.onClick}>Hello {props.name}</h1>
また、onClickにはハンドラ関数を渡すため、型チェックのルールは次のようになります。
onClick: PropTypes.func
StateとLifecycleイベント
Stateをコンポーネントに追加する
ES6のクラス構文で初期化処理を行うためには、constructorを使います。
React.Componentはstateと呼ばれる特別はプロパティをStateとして利用しています。
これを初期化するには、コンポーネントの初期化処理で、初期値(今回の場合は現在日時のDateオブジェクト)を設定して初期化します。
constructor() {
this.state = {
data: new Date();
}
}
stateはimmutable(不変)なオブジェクトであるため、一度初期化した後は直接これを変更することができません。これを変更するためにはsetStateを使います。
また、ES6のクラス構文では(extendsを利用している)子クラスは、superで親クラスを初期化するまでthisのスコープを利用することはできません。
そのため、React.Componentを使ったReactコンポーネントは、次のようにsuperでReact.Componentを初期化した後に、Stateを初期化します。
constructor(props) {
super(props);
this.state = {
data: new Date();
}
}
コンポーネントの中でStateの値を利用するためには、this.stateオブジェクトを参照します。
this.state.date.toLocaleTimeString()
componentDidMount
コンポーネントがマウントされた後に何かの処理を実行するためには、componentDidMount()をコンポーネントに追加します。
componentDidMount() {
// 何かの処理
}
componentDidMountはLifecycle関数と呼ばれるもので、Reactコンポーネントが処理されるさまざまな過程で部分的に処理を挟み込むことが可能です。
Stateを変更する
Stateの値を更新するためにはsetState関数を利用します。
this.setState({ date: new Date() });
Stateはimmutable(不変)なオブジェクトであるため、次のように直接変更してはいけません。
this.state.date = new Date();
setStateでStateが変更された場合、Reactはその変更を検知してReactDOM.renderに再描画を依頼します。
ReactDOM.renderは、変更されたノードのみを抽出し、これを再描画します。
そのため、正規の手順に従いStateを更新しない限り、画面が再描画されることはありません。
componentWillUnmount
コンポーネントが破棄される前に何か処理を実行するためには、componentWillUnmountをコンポーネントに追加します。
componentWillUnmount() {
// なにかの処理
}
配列データ構造の扱い方
配列データを1つずつ処理する
配列を順に処理するためにはmap関数を利用します。
配列からコンポーネントを作成する
配列からItemコンポーネントを作成するためには、次のように記述します。
<Item item={item} />
keyをリストに設定する
Itemコンポーネントのkey属性を設定するには、次のように記述します。
<Item key={item.id} item={item} />
keyとは、Reactの中でどのコンポーネントが追加・変更・削除されたかを識別するために利用されます。
keyには、何か一意となるようなIDを指定することが望ましいとされてます。
例えば、item.idのようにデータベースで割り振られているような一意なID
もしそのような一意なIDが無い場合は、配列操作のインデックスを設定することもできますが、これはReactのアンチパターンの一つとしてよく知られているため、インデックスをkeyに利用するべきではありません。
入力フィールドの扱い方
入力フィールドとStateを関連づける
Stateの値を初期化するためには、コンポーネントのconstructorにて次のようにStateを初期化します。
this.state = {
value: "CODEPREP"
};
これを入力フィールドの初期値に設定するには、value属性にStateの値を設定します。
<input name="name" value={this.state.value} />
入力フィールドのChangeハンドラを作る
Stateを変更するためには、this.setStateを利用します。
this.setState({ value });
このようなStateで管理されている入力フィールドのことをControlled Componentsと呼びます。
それに対し、Stateで管理されていない入力フィールドのことをUncontrolled Componentsと呼びます。
ReactはsetStateでStateの値が変更された時にDOMを再描画するため、直接value属性を変更しただけでは画面は再描画されません。
そのため、入力フィールドが変更できないように見えます。
Changeハンドラのコンテキストを固定する
handleChangeハンドラのコンテキストをFormコンポーネントに固定するためには、bind関数にthisを渡します。
this.handleChange = this.handleChange.bind(this);
FormコンポーネントはReact.Componentを継承しているためthisはReact.Componentになります。
コンポーネントのイベントハンドラなどからコンポーネントの関数を呼び出す場合、thisコンテストがundefinedになります。
そのため、このテクニックはReact.Componentでコンポーネントを作成した場合、非常によく使うテクニックです。
Changeハンドラを入力フィールドに設定する
コンポーネントのchangeイベントでhandleChangeハンドラを呼び出すようにするためには、次のように記述します。
<input
name="name"
value={this.state.value}
onChange={this.handleChange}
/>
ReactのuseStateとpropsの基本
Reactを学び始めたばかりの方へ、Reactの基本的な概念であるuseStateとpropsについて解説します。これらの概念を理解することで、Reactでのアプリケーション開発がよりスムーズになります。
useStateとは?
useStateは、Reactのフックの一つで、関数コンポーネントで状態管理を行うための機能です。クラスコンポーネントではthis.stateを使って状態を管理していましたが、useStateを使うことで関数コンポーネントでも状態を扱うことができるようになります。
使用例:
import React, { useState } from 'react';
function Counter() {
// 初期値0でcount状態を作成し、setCountで更新する
const [count, setCount] = useState(0);
return (
<div>
<p>現在のカウント: {count}</p>
<button onClick={() => setCount(count + 1)}>カウントアップ</button>
</div>
);
}
このコードでは、countという状態を持ち、ボタンをクリックすることでその値が1ずつ増加します。
propsとは?
props(プロパティ)は、Reactでコンポーネント間でデータを渡すための仕組みです。親コンポーネントから子コンポーネントへデータを渡す際に使用され、読み取り専用のデータとして扱われます。
使用例
親コンポーネント:
import React from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
return <ChildComponent greeting="Hello" />;
}
子コンポーネント:
import React from 'react';
function ChildComponent(props) {
return <h1>{props.greeting}, world!</h1>;
}
ここでは、ParentComponentからChildComponentにgreetingという名前のpropsを渡しています。ChildComponentはこのgreetingを受け取り、表示しています。