コンポーネント
コンポーネントとは、見た目(テンプレート)とロジック(振る舞い)をひとまとめにし、再利用可能なUI部品として切り出した単位のこと。React をはじめとするフロントエンドフレームワークでは、アプリケーションを構造的に組み立てるための基本的な単位として用いられる。
なぜ必要なのか
アプリケーションが大規模になると、1つの HTML や JavaScript ファイルで全体を管理するのは困難になる。そのため、関心ごとの分離や UI の再利用性の向上 を目的として、機能や見た目をする必要がある。これにより、保守性・可読性が高まり、チームでの分担開発もしやすくなる。
関数コンポーネントとクラスコンポーネント
React でコンポーネントを定義する方法には、主に以下の2つがある。
関数コンポーネント
関数として定義されるコンポーネント。React Hooks(useState, useEffect など)の導入により、状態管理や副作用の処理も関数内でシンプルに記述できるようになった。
function Hello() {
return <h1>Hello, world!</h1>;
}
クラスコンポーネント
クラスとして定義されるコンポーネント。かつては主流だったが、現在は関数コンポーネントに置き換えられており、非推奨となっている。
class Hello extends React.Component {
render() {
return <h1>Hello, world!</h1>;
}
}
コンポーネント名は大文字から始める必要がある。そうでない場合、動作しない。また、コンポーネントの定義をネストさせてはいけない。
「純粋」に保つのが基本
関数コンポーネントは、毎回まっさらな状態で実行される関数である。その中でデータを直接書き換えたり、画面を操作したりすると、思わぬ動作になることがある。React では「同じ入力に対して同じ見た目を返す」という、純粋な関数のような書き方が基本である。画面に出す内容は props や state によって決まり、それ以外の処理(データの取得やログ出力など)は別の場所で扱うのがよい。
純粋な関数とは、同じ入力に対して、必ず同じ出力を返す関数のこと。たとえば f(x) = x * 2 は、x が同じなら何度呼んでも結果は同じなので純粋。一方で、関数の中でランダムな値を使ったり、外の変数を変更したりすると、呼ぶたびに結果が変わるため「純粋ではない」。
Props
Props とは、親コンポーネントから子コンポーネントへデータを渡すための仕組み。オブジェクトや配列、関数などのあらゆる JavaScript の値を渡すことができる。
なぜ必要なのか
Props は、親コンポーネントから子コンポーネントにデータを渡すための仕組みであり、たとえば「名前を表示するパーツ」に名前を渡したいとき、Props を使えばいろいろな名前で同じパーツを使い回すことができる。これにより、コンポーネントをわかりやすく、整理された形で作ることが可能となる。React では、データは親から子へ一方向に流れるというルールがあり、それを守るためにも Props が必要となる。
使い方
親コンポーネントからの渡し方
親コンポーネントでは、子コンポーネントのタグに属性のようにして値を渡す。文字列以外を渡す場合、JSX のルールに基づき {} を使用する。
function App() {
return <Greeting name="太郎" age={20} />;
}
子コンポーネントでの受け取り方
子コンポーネントでは、props 引数を使って値を受け取る。分割代入を使えば、必要な値だけを取り出せる。また、デフォルト値を設定することもできる。
type GreetingProps = {
name: string;
age: number;
};
function Greeting({ name, age = 25}: GreetingProps) {
return (
<p>
こんにちは、{name}さん!{age}歳ですね。
</p>
);
}
function Greeting(props: GreetingProps) {
return (
<p>
こんにちは、{props.name}さん!{props.age}歳ですね。
</p>
);
}
Props はイミュータブルであるため、子コンポーネント側で書き換えることはできない。
State
State とは、コンポーネントが持つ「変化するデータ」のこと。ユーザーの操作に応じて変化し、そのたびにコンポーネントが再レンダリングされる。たとえば、フォーム入力や画像の切り替え、買い物かごの中身などを覚えておくために使う。
なぜ必要なのか
単なる変数でデータを管理すると、その変数が変わっても React は画面の更新を行わない。なぜなら、React はコンポーネントの関数が再実行されることで初めて画面を再レンダリングするからだ。また、関数コンポーネントは呼ばれるたびに内部の変数が初期化されるため、値を保持できない。そこで、State を使ってデータを管理すると、データが変わるたびに React が自動的に画面を更新し、かつ値も保持してくれる。
使い方
State を利用するには、useState というフックを利用する。
フックとは、関数コンポーネントで state やライフサイクルなどの React の機能を利用できるようにする機能
基本構文
-
state: 現在の状態の値 -
setState: 状態を更新するための関数(再レンダリングを引き起こす) -
useState(...): 初期状態を設定(1回だけ実行される)
const [state, setState] = useState(初期値);
以下のコードはカウンタの例である。state は自由に命名してよく、setState は set というプレフィックスをつけるのが慣例となっている。また、useState をはじめとするフックはコンポーネントのトップレベルでのみ呼び出すことができる。条件分岐、ループ、ネストされた関数の中でフックを呼び出すことはできない。
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // 初期値は0
return (
<div>
<p>現在のカウント: {count}</p>
<button onClick={() => setCount(count + 1)}>増やす</button>
</div>
);
}
prevState
prevState とは、React の setState を使って状態を更新する際に使う「直前の状態(state)の値」のこと。setState には、新しい値の代わりに 関数(アップデート関数) を渡すことができ、その関数の引数として渡ってくるのが prevState になる。
なぜ必要なのか
React の状態更新は 非同期でバッチ処理されるため、以下のように「今の状態に基づいて次の状態を決めたい」ケースでは、現在の state を直接参照するだけでは正しい結果にならない可能性がある。
// ❌ 状況によって正しく動作しない可能性がある
setCount(count + 1);
setCount(count + 1);
このようなコードは、count がまだ更新されていない状態で setCount を連続して呼び出してしまうため、意図した通りに +2 されないことがある。
使い方
setState に関数を渡すことで、常に最新の状態をもとに次の状態を計算できる。
// ✅ 連続で 2 増やしたい場合も、こう書けば安全
setCount(prev => prev + 1);
setCount(prev => prev + 1);
再レンダリングのタイミング
React のコンポーネントは、使っている State や Props が変わったときに自動で画面を描き直す。また、親コンポーネントが変わると、子もあわせて描き直されるのが基本。見た目に変化がなくても、親が動くと子も動くことがある。
イベント
イベント とは、ユーザーの操作やブラウザの動作によって発生するアクションのこと。たとえば「ボタンをクリックした」「キーボードが押された」「フォームが送信された」など、ユーザーインターフェースに対する反応を検知し、それに応じた処理を実行するために使う。React では、これらのイベントを HTML と似た構文で扱えるが、実際にはブラウザ依存の挙動を吸収した React 独自の「合成イベントシステム」 によって一貫した挙動が提供されている。
なぜ必要なのか
アプリケーションに対してユーザーが操作を行ったときに、それに応じた反応をさせるためにイベントは不可欠。React のイベントは、JavaScript の addEventListener を使わず、より宣言的・簡潔にイベント処理を記述できる。また、React 内部でイベント処理が最適化されており、パフォーマンスや保守性にも優れている。
使い方
React では、イベント名を キャメルケース(例:onClick, onChange) で記述し、イベントハンドラには関数を直接渡す。
function Button() {
const handleClick = () => {
alert("クリックされました!");
};
return <button onClick={handleClick}>クリック</button>;
}
渡すべきは関数であって、呼び出すべきではない。 つまり、()をつけずに関数名だけを書く。
よく使われるイベント
| イベント名 | 説明 |
|---|---|
onClick |
ボタンや要素がクリックされたとき |
onChange |
入力値やセレクトボックスが変更されたとき |
onSubmit |
フォームが送信されたとき |
onKeyDown |
キーが押されたとき(押下) |
onKeyUp |
キーが離されたとき(離す) |
onFocus |
フォーカスが当たったとき |
onBlur |
フォーカスが外れたとき |
onMouseEnter |
マウスが要素に入ったとき |
onMouseLeave |
マウスが要素から出たとき |
イベントハンドラには、React の合成イベントオブジェクトが渡される。これは event.target.value のように、通常の DOM イベントと同じように扱えるが、React 独自にラップされており、ブラウザ間の違いを吸収している。
任意の引数を渡す方法
React のイベントハンドラに 任意の引数を渡したい場合 は、無名関数(アロー関数) を使うのが基本。直接関数を呼び出すと、その場で実行されてしまうため注意が必要。
<button onClick={handleClick("太郎")}>クリック</button>; // ❌ 呼び出し済み
<button onClick={() => handleClick("太郎")}>クリック</button>; // ✅ 遅延実行
key
key とは、React がリスト(配列)をレンダリングするときに、各要素を一意に識別するための特別な属性のこと。要素を追加・削除・並び替えたときに、React が「どの要素が変わったか」「どれを再利用するか」を正しく判断できるようになる。
なぜ必要なのか
React は仮想 DOM を使って効率的に差分を検出・更新しているが、その際にリストの中でどの要素が変化したのかを識別する手がかりが必要になる。key がない、あるいは不適切な key(たとえばインデックスなど)を使っていると、React は要素を誤って削除・再生成することがあり、意図しない再レンダリングや状態リセット(たとえば入力値の消失)などのバグにつながる。
仮想 DOM とは、ブラウザの画面上にある DOM を JavaScript の中に仮想的に再現したもの。React は実際の DOM を直接操作せず、まず仮想DOM上で変更を行い、変更前後の差分を比較して、必要な部分だけを実際の DOM に反映する。
使い方
key 属性をつけることで、React がリストの各要素を一意に識別できるようになる。タグだけでなく、カスタムコンポーネントに対しても使用できる。値には、重複しない一意な ID やコードなどを使うのが基本である。
const users = [
{ id: 1, name: '田中 太郎' },
{ id: 2, name: '佐藤 花子' },
];
function UserList() {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li> // ✅ key に一意な id を使用
))}
</ul>
);
}
function UserList() {
return (
<div>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}
一意なキーを生成するだけならば、randomUUID() メソッドを使うのも有効。
key を使わなかった場合、Warning: Each child in a list should have a unique “key” prop. という警告が出る。
children
children とは、コンポーネントの開始タグと終了タグのあいだに書かれた内容(子要素)を受け取るための特別な propsのこと。React では、親コンポーネントから子コンポーネントへ、要素やコンテンツを渡すときに使う。
なぜ必要なのか
children を使うことで、汎用的で再利用性の高いコンポーネントを作ることができる。たとえばボタン、レイアウト、ダイアログのようなコンポーネントで、中に入れる要素を外から差し込む構造が必要な場合に便利である。
使い方
children は、関数コンポーネントの引数として props から受け取り、タグ内に挿入することで表示できる。
type Props = {
children: React.ReactNode;
};
function MyComponent({ children }: Props) {
return (
<div className="my-component">
{children}
</div>
);
}
<MyComponent>
<p>Hello</p>
<p>World</p>
</MyComponent>
通常の props との使い分け
| 種類 | 用途 | 例 |
|---|---|---|
通常の props
|
コンポーネントの設定情報や振る舞いを制御する |
type="primary", size="small", id="input-1"
|
children |
コンポーネントの中身の要素を差し込む | ボタンのラベル、カードの本文、リストのアイテムなど |
スタイル
React では、コンポーネントごとにスタイルを当てる方法がいくつか用意されている。用途やスケールに応じて適切な手法を選ぶことで、保守性や再利用性が高まる。
| 方法 | 特徴 | 向いている場面 |
|---|---|---|
| インラインスタイル | コンポーネント内で直接指定。スタイルが JavaScript オブジェクト形式 | 小規模、動的に値を変えるとき |
| CSS モジュール |
.module.css ファイルを import。クラス名が自動的にユニーク化される |
中規模、スコープを分離したいとき |
| 外部 CSS ファイル | 通常の CSS を import して使用 | 全体スタイルやグローバルテーマに向く |
| styled-components(CSS-in-JS) | スタイルとコンポーネントを一体化。JS 内で記述できる | コンポーネントごとの管理や動的スタイルに強い |
インラインスタイル
function Box() {
return <div style={{ color: 'red', fontSize: '20px' }}>赤い文字</div>;
}
- CSS プロパティはキャメルケース(
font-size→fontSize) -
:hoverやメディアクエリには対応できない
CSS モジュール
.title {
color: blue;
font-size: 24px;
}
import styles from './styles.module.css';
function Title() {
return <h1 className={styles.title}>タイトル</h1>;
}
- クラス名の衝突を防げる
- スコープがコンポーネント内に限定される
外部 CSS ファイルの import
.global-title {
color: green;
}
import './styles.css';
function Title() {
return <h1 className="global-title">タイトル</h1>;
}
- アプリ全体にスタイルを適用したいときに便利
- クラス名の重複リスクがあるので管理に注意
styled-components(CSS-in-JS)
import styled from 'styled-components';
const Button = styled.button`
background: tomato;
color: white;
padding: 8px 16px;
border-radius: 4px;
&:hover {
background: darkred;
}
`;
function App() {
return <Button>送信</Button>;
}
- JavaScript の文脈内でスタイルを完結できる
- コンポーネントごとにスタイルを閉じ込めやすい
- ただし初期学習コストとランタイムの依存がある
動的なスタイル
インラインスタイルや styled-components では、props の値に応じてスタイルを変えることも可能。
const Box = styled.div<{ highlight: boolean }>`
background: ${({ highlight }) => (highlight ? 'yellow' : 'white')};
`;
<Box highlight={true}>ハイライト</Box>
条件付きレンダリング
React では、表示を条件によって切り替えたいときに、JSX 内で if 文を使うことはできない。そこで、三項演算子(? :) や 論理 AND(&&)、即時実行関数(IIFE) を使って条件付きでレンダリングを行う。
?:(三項演算子)
条件によって 2 通りの表示を切り替えたいときに使う。
<p>{isLoggedIn ? "ようこそ" : "ログインしてください"}</p>
&&(論理 AND)
「この条件のときだけ表示したい」という場合に使う。条件が true のときだけ右側が実行され、false のときは何も表示されない。
{isAdmin && <p>管理者メニュー</p>}
即時実行関数
複雑な条件分岐をしたいときに使う方法。関数をその場で定義してすぐに実行する。
function Message({ user }: { user: string | null }) {
return (
<div>
{(() => {
if (!user) return <p>ログインしてください</p>;
if (user === 'admin') return <p>管理者としてログイン中</p>;
return <p>{user} さん、こんにちは</p>;
})()}
</div>
);
}
複雑な分岐があるときは、いったん変数に入れてから JSX に書く方が読みやすくなることもある。
子から親への情報伝達
親から子へ情報を渡すには Props を利用するが、子から親へはどうするのだろうか。子から親へ情報を渡すには State を利用する。子コンポーネントから親コンポーネントの State を更新することで情報を伝える。
export function Parent() {
const [message, setMessage] = useState("まだ何もありません");
return (
<div>
<h2>親コンポーネント</h2>
<p>メッセージ: {message}</p>
<Child onSend={(msg) => setMessage(msg)} />
</div>
);
}
type Props = {
onSend: (msg: string) => void;
};
export function Child({ onSend }: Props) {
const sendToParent = () => {
onSend("子からのメッセージです!");
};
return (
<div>
<h3>子コンポーネント</h3>
<button onClick={sendToParent}>親にメッセージを送る</button>
</div>
);
}
React Developer Tools
React Developer Tools とは、React コンポーネントの構造や状態(state、props)をブラウザ上で確認・デバッグできる開発者向けツールである。
Components タブ
React のコンポーネントツリーがツリー状に表示され、各コンポーネントをクリックすると props や state、hooks の値が表示される。値を直接編集すると、UI にリアルタイム反映される(状態デバッグに便利)。
Profiler タブ
コンポーネントの描画コスト(再レンダリングの頻度や時間)を分析や、パフォーマンスの最適化に役立つ。
参考