はじめに
Reactは、Facebookが開発したJavaScriptのライブラリで、ユーザーインターフェイス(UI)の構築に使用されます。Reactは、コンポーネントベースのアプローチを採用しており、再利用可能なUIの部品を作成することができます。
Reactの主な特徴は以下の通りです。
仮想DOM(Virtual DOM):Reactは、仮想DOMを使用して効率的にUIを更新します。
仮想DOMは、実際のDOMの軽量なコピーで、変更の検出と適用を最適化します。
コンポーネントベース:Reactは、UIをコンポーネントに分割することを推奨します。コンポーネントは、独立した再利用可能な部品で、プロパティ(props)を受け取り、JSXを使ってレンダリングします。
単方向データフロー:Reactでは、データは親コンポーネントから子コンポーネントへと一方向に流れます。これにより、アプリケーションの状態管理が簡素化されます。
JSX:ReactではJSXと呼ばれる構文を使用します。JSXは、JavaScriptにXMLライクな記法を導入し、コンポーネントのレンダリングを宣言的に記述できます。
これらの特徴により、Reactは大規模で複雑なUIの開発に適しています。
1.コンポーネントの作成
Reactでは、UIの構成要素をコンポーネントとして定義します。コンポーネントは、関数コンポーネントとクラスコンポーネントの2種類があります。
1.1関数コンポーネント
関数コンポーネントは、propsを受け取り、JSXを返す関数です。関数コンポーネントは、状態を持たない単純なコンポーネントを作成するために使用されます。
例えば、「Hello, [名前]!」と表示するコンポーネントを作成するとします。
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
function App() {
return (
<div>
<Greeting name="Alice" />
<Greeting name="Bob" />
</div>
);
}
ここでは、
Greeting
コンポーネントはname
というprop
を受け取っています。このprop
は、コンポーネントを使用する側から渡されます。
Appコンポーネントでは、Greeting
コンポーネントを2回使用しています。その際、nameprop
に異なる値("Alice"
と"Bob"
)を渡しています。
これにより、Greeting
コンポーネントは次のようにレンダリングされます。
<div>
<h1>Hello, Alice!</h1>
<h1>Hello, Bob!</h1>
</div>
1.2クラスコンポーネント
クラスコンポーネントは、React.Component
を継承したクラスです。クラスコンポーネントは、状態(state
)を持つことができ、ライフサイクルメソッドを使用できます。
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Increment
</button>
</div>
);
}
}
上記の例では、Counter
というクラスコンポーネントを定義しています。constructor
メソッド内で初期状態を設定し、render
メソッド内でJSXをレンダリングしています。this.state
を使って状態にアクセスし、this.setState
を使って状態を更新しています。
2.JSXの使い方
JSXは、JavaScriptの構文拡張で、HTMLライクな記法でコンポーネントのレンダリングを記述できます。JSXは、最終的にReactのcreateElement関数に変換されます。
const element = (
<div>
<h1>Hello, World!</h1>
<p>This is a JSX example.</p>
</div>
);
上記の例では、JSXを使ってdiv
要素の中にh1
要素とp
要素を記述しています。JSXは、1つの親要素で囲む必要があります。
JSXの中では、JavaScriptの式を中括弧{}
で囲むことで埋め込むことができます。
const name = "John";
const element = <h1>Hello, {name}!</h1>;
上記の例では、name
変数の値をJSXの中で使用しています。
3.propsの受け渡し
propsは、コンポーネントに渡されるデータを表します。propsは、親コンポーネントから子コンポーネントへと受け渡されます。
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
function App() {
return (
<div>
<Greeting name="John" />
<Greeting name="Jane" />
</div>
);
}
上記の例では、App
コンポーネントからGreeting
コンポーネントにname
プロパティを渡しています。Greeting
コンポーネントは、props.name
を使ってデータにアクセスしています。
4.イベントハンドリング
関数コンポーネントでイベントハンドリングを行うには、JSXの中でイベントハンドラを指定します。イベントハンドラは、ユーザーの操作に応じて呼び出される関数です。
import React from 'react';
function Button() {
function handleClick() {
console.log("Button clicked!");
}
return <button onClick={handleClick}>Click me</button>;
}
上記の例では、Button
コンポーネントがhandleClick
関数をイベントハンドラとして使用しています。ボタンがクリックされると、handleClick
関数が呼び出されます。
ほかにもさまざまなイベントハンドラがあります。
イベントハンドラ | 説明 |
---|---|
onClick |
要素がクリックされたときに呼び出されます |
onSubmit |
フォームが送信されたときに呼び出されます |
onChange |
フォームの入力値が変更されたときに呼び出されます |
onMouseOver |
マウスポインターが要素の上に移動したときに呼び出されます |
onMouseOut |
マウスポインターが要素の上から離れたときに呼び出されます |
onKeyDown |
キーが押されたときに呼び出されます |
onKeyUp |
キーが離されたときに呼び出されます |
これらのイベントハンドラを使って、ユーザーの操作に応じた処理を実装できます。
5.コンディショナルレンダリング
関数コンポーネントでコンディショナルレンダリングを行うには、JSXの中で条件式を使用します。
import React from 'react';
function Greeting(props) {
if (props.isLoggedIn) {
return <h1>Welcome back</h1>;
} else {
return <h1>Please sign up</h1>;
}
}
このGreeting
コンポーネントは、ユーザーがログインしているかどうかに応じてレンダリングする要素を決定します。
・props
オブジェクトからisLoggedIn
プロパティを受け取ります。
・isLoggedIn
がtrue
の場合は、Welcome backを返します。
・isLoggedIn
がfalse
の場合は、Please sign upを返します。
つまり、このコンポーネントは、ログイン状態に応じて適切なメッセージを表示するための簡単な条件分岐ロジックを持っているのです。
親コンポーネントがisLoggedIn
の値を適切に設定すれば、このコンポーネントは正しい挨拶メッセージを表示することができます。
import React from 'react';
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
function App() {
const numbers = [1, 2, 3, 4, 5];
return (
<NumberList numbers={numbers} />
);
}
NumberList コンポーネント
・props
オブジェクトから numbers
プロパティを受け取ります。
・numbers
配列の各要素に対して map()
関数を使い、listItems
という配列を生成します。
・map()
関数の中で、各要素に対して <li>
要素を作成しています。
・key
プロパティには、各要素の一意の識別子として number.toString()
を設定しています。これは React が DOM の効率的な更新を行うために重要です。
・最終的に <ul>
要素の中に listItems
配列をレンダリングしています。
App コンポーネント
・numbers
という配列を定義しています。
・<NumberList>
コンポーネントを呼び出し、numbers
配列を numbers
プロパティとして渡しています。
レンダリングの流れは以下のようになります。
・App
コンポーネントがレンダリングされると、numbers
配列が定義されます。
・<NumberList>
コンポーネントがレンダリングされ、numbers
プロパティに [1, 2, 3, 4, 5]
が渡されます。
・NumberList
コンポーネントの map()
関数が呼ばれ、listItems
配列が生成されます。
・listItems
配列の各要素が <li>
要素としてレンダリングされ、<ul>
要素の中に表示されます。
このようにして、React の関数コンポーネントを使って配列からリストをレンダリングする基本的な例が実装されています。key
プロパティの設定は、Reactが効率的にリストの更新を行うために重要な部分です。
7.Hooks
Hooksは、関数コンポーネントに状態や副作用を追加するための機能です。
useState
、useEffect
フックとuseContext
フックについて説明します。
7.1useState
useStateフックは、関数コンポーネントに状態を追加するために使用します。
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
・const [count, setCount] = useState(0);
という行で、初期値を 0
としたステート変数 count
と、それを更新するための関数 setCount
を定義しています。
・<p>Count: {count}</p>
により、現在のカウンターの値を表示しています。
・<button onClick={() => setCount(count + 1)}>Increment</button>
により、ボタンをクリックすると setCount
関数を呼び出し、count
の値を 1 増やしています。
具体的な流れは以下の通りです。
1.コンポーネントがレンダリングされると、useState(0)
により初期の count
値が 0 に設定されます。
2.<p>Count: {count}</p>
によって、現在の count
値が 0 と表示されます。
3.ユーザーがボタンをクリックすると、onClick
イベントハンドラが発火します。
4.ハンドラ内の setCount(count + 1)
が実行され、count
の値が 1 に更新されます。
5.React は、count
値の変更を検知し、コンポーネントを再レンダリングします。
6.新しい count
値 1 が <p>Count: {count}</p>
に反映されます。
このように、React の useState
フックを使うことで、コンポーネント内部のステート管理が簡単に行えます。ステートの更新に応じて、コンポーネントが効率的に再レンダリングされるのが特徴です。
7.2useEffect
useEffect
フックは、関数コンポーネントに副作用を追加するために使用します。
副作用とは、データの取得、サブスクリプション、タイマーなどの外部システムとのインタラクションを意味します。
import React, { useState, useEffect } from 'react';
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(prevCount => prevCount + 1);
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
return <h1>Count: {count}</h1>;
}
このコードは、React の useEffect
フックを使って、1秒ごとにカウントを増やすタイマーのサンプルです。
・useEffect(() => { ... }, []);
により、コンポーネントがマウントされたときに一度だけ実行されるエフェクトを定義しています。
・エフェクト内部で、setInterval()
を使って 1 秒ごとに setCount
を呼び出し、count
の値を 1 ずつ増やしています。
・返り値の関数 () => { clearInterval(timer); }
は、コンポーネントがアンマウントされたときに呼び出され、setInterval
のタイマーをクリアしています。
・<h1>Count: {count}</h1>
により、現在の count
値を表示しています。
具体的な流れは以下の通りです。
1.コンポーネントがマウントされると、useEffect
のコールバック関数が実行されます。
2.setInterval
が呼び出され、1 秒ごとに setCount(prevCount => prevCount + 1)
が実行されます。これにより、count
値が 1 ずつ増えていきます。
3.count
値の変更に応じて、React はコンポーネントを再レンダリングし、<h1>Count: {count}</h1>
に新しい値が表示されます。
4.コンポーネントがアンマウントされると、useEffect
で返された関数が呼び出され、setInterval
のタイマーがクリアされます。
このように、useEffect
フックを使うことで、コンポーネントのライフサイクルに合わせて副作用を管理することができます。タイマーの開始と停止を適切に行うことで、メモリリークを防ぐことができます。
7.3useContext
useContextフックは、コンテキストを使用して、コンポーネント間でデータを共有するために使用します。
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme === 'dark' ? 'black' : 'white' }}>
Themed Button
</button>
);
}
このコードは、React の useContext
フックを使って、テーマの状態を管理する例です。
const ThemeContext = React.createContext('light');
により、テーマコンテキストを作成しています。
初期値は "light" に設定されています。
<ThemeContext.Provider value="dark">
により、テーマコンテキストの値を "dark" に設定しています。
<Toolbar />
コンポーネントをレンダリングしています。
<ThemedButton />
コンポーネントをレンダリングしています。
const theme = useContext(ThemeContext);
により、テーマコンテキストの値を取得しています。
<button style={{ background: theme === 'dark' ? 'black' : 'white' }}>
により、テーマに応じてボタンの背景色を変更しています。
具体的な流れは以下の通りです。
1.App
コンポーネントがレンダリングされると、<ThemeContext.Provider>
によってテーマコンテキストの値が "dark" に設定されます。
2.Toolbar
コンポーネントがレンダリングされ、その子である ThemedButton
コンポーネントが描画されます。
3.ThemedButton
では、useContext(ThemeContext)
によって "dark" のテーマ値を取得しています。
4.取得したテーマ値に応じて、ボタンの背景色が動的に変更されています。
このように、useContext
フックを使うことで、コンポーネント階層の任意の場所からコンテキストの値を取得することができます。これにより、テーマの変更などのグローバルな状態管理を簡単に実現できます。
まとめ
この記事では、Reactの基礎的な概念について説明しました。
Reactは、コンポーネントベースのアプローチを採用しており、再利用可能で保守性の高いUIを構築するための強力なツールです。この記事で紹介した概念を理解することで、Reactを使ったWebアプリケーションの開発に必要な基礎知識が身につきます。
Reactの学習には時間と練習が必要ですが、公式ドキュメントやチュートリアルを参考に、実際にコードを書いて試すことが大切です。この記事を出発点として、Reactの理解を深めていってください。