TypeScriptでの開発に慣れてきたけれど、「React」については今ひとつ理解が曖昧……そんな悩みを抱えていませんか?
Reactは、現代のフロントエンド開発において欠かせないUIライブラリであり、多くの企業やプロジェクトで採用されています。
本記事では、「今さら聞けないけど知っておきたい」Reactの基本を、TypeScript開発者の視点からわかりやすく解説します。
これからReactを学びたい方や、基礎を整理したい方は、ぜひ最後までご覧ください。
Reactとは? UI構築に特化した人気ライブラリ
Reactは、Webアプリケーションのユーザーインターフェース(UI)を構築するためのJavaScriptライブラリです。Facebook(現Meta)社が開発し、現在はオープンソースとして世界中の開発者に支持されています。
「ライブラリ」と聞くと「フレームワークと何が違うの?」という疑問が浮かぶかもしれません。
大きな違いは、アプリ全体の構造まで提供するか否かです。
- フレームワーク:アプリ全体の構造・流れを規定
- ライブラリ(React):特定の目的(UI構築)に特化。必要に応じて組み合わせて使う
Reactは、UI構築に専念するミニマルな設計。ルーティングや状態管理といった機能は、React RouterやRedux、Zustandなど他のライブラリと組み合わせて構築していきます。
Reactのコア思想:コンポーネント志向と宣言的UI
Reactを理解する上で欠かせないのが、「コンポーネント」と「宣言的UI」という2つのキーワードです。
コンポーネント志向
ReactではUIを「部品」として再利用可能なコンポーネントに分割します。
たとえば、ボタン、ヘッダー、リスト表示など、それぞれを独立したパーツとして定義し、組み合わせることでページを構築します。
これにより、次のようなメリットがあります:
- 再利用がしやすい
- コードの見通しが良くなる
- 保守・変更が局所的に行える
宣言的UI
Reactでは、「UIの最終的な状態」を記述するだけで、内部的なDOM操作をReactが担ってくれます。
{isLoggedIn ? <Welcome /> : <Login />}
このように「状態に応じて表示する要素を宣言」することで、複雑なUIロジックも直感的に記述できます。
TypeScriptと相性抜群なReactのメリットまとめ
Reactがここまで広く普及している理由には、TypeScriptとの相性の良さをはじめ、以下のような魅力があります。
再利用しやすく効率的な開発
UIパーツをコンポーネントとして使い回せるため、重複したコードの記述を削減。開発スピードが加速します。
高い保守性
コンポーネントごとに機能を分離できるため、変更やバグの影響範囲を局所化できます。
高速なレンダリング(仮想DOM)
Reactは、仮想DOMによって最小限の差分だけを実際のDOMに反映。これにより、パフォーマンスの高いUI更新が可能になります。
豊富なライブラリと活発なコミュニティ
人気の高さゆえに、Reactに対応したツールや情報は豊富。TypeScript対応の型定義も揃っており、導入障壁は低めです。
【実践】Reactを使ってカレンダーアプリを作成する
ここからはさらにステップアップ! ReactとTypeScriptを組み合わせて、簡単なカレンダーアプリを作成する手順を解説します。
1. プロジェクト作成
まずは、React + TypeScriptプロジェクトのひな形を作成します。ここでは、React公式が提供する開発ツール「Create React App」を使用します。(よりモダンな開発ではViteも選択肢となりますが、今回はCreate React Appの手順で進めます。)
ターミナルを開き、以下のコマンドを実行してください。
npx create-react-app ait-calendar-app7 --template typescript
cd ait-calendar-app7
npm start
このコマンドで、create-react-app
というツールを使って、ait-calendar-app7
という名前の新しいディレクトリを作成できます。
そして、その中にReactとTypeScript、および開発に必要な各種設定ファイルをまとめてセットアップしてくれます。
実行中に次のようなメッセージが表示されたら、y
を入力してEnterを押します。
Need to install the following packages:
create-react-app@5.1.0
Ok to proceed? (y)
数秒待つと開発サーバーが起動し、自動的にブラウザでhttp://localhost:3000
が開かれます。
以下のような、Reactのロゴが表示された初期画面が表示されるはずです。

ターミナルには、開発サーバーが起動し、コンパイルが成功したことを示すメッセージが出力されています。
Compiled successfully!
You can now view ait-calendar-app7 in the browser.
Local: http://localhost:3000
On Your Network: http://192.168.151.123:3000Note that the development build is not optimized.
To create a production build, use npm run build.webpack compiled successfully
No issues found.
これが、これから開発を進めていくプロジェクトのベースとなります。
フォルダ構造
VScode上で、以下のファイルが作成されていることを確認してください。

プロジェクトのフォルダ構造は、以下のようになっています。
ait-calendar-app7/
├── node_modules/ # 依存パッケージがインストールされるディレクトリ
├── public/ # 静的ファイル(HTML, 画像など)を格納するディレクトリ
├── src/ # アプリのソースコードを格納するディレクトリ
│ ├── App.css # アプリ全体のスタイル定義
│ ├── App.test.tsx # Appコンポーネントのテストファイル
│ ├── App.tsx # アプリのメインReactコンポーネント
│ ├── index.css # グローバルスタイル定義
│ ├── index.tsx # Reactアプリのエントリーポイント
│ ├── logo.svg # アプリロゴ画像(SVG形式)
│ ├── react-app-env.d.ts # Reactアプリ用の型定義ファイル(環境補完用)
│ ├── reportWebVitals.ts # パフォーマンス測定用の設定ファイル
│ └── setupTests.ts # テスト前のセットアップ設定ファイル
├── .gitignore # Git管理対象外にするファイルやフォルダのリスト
├── package-lock.json # 依存パッケージの正確なバージョンをロックするファイル
├── package.json # プロジェクトの依存関係やスクリプトを管理するファイル
├── README.md # プロジェクトの概要や使い方を記述するファイル
└── tsconfig.json # TypeScriptのコンパイル設定ファイル
主に開発を行うのは、src
ディレクトリの中になります。
src/App.tsx
がアプリケーションのメインコンポーネントです。
カレンダーの初期画面に変更する
開発サーバーが起動している状態で、src/App.tsx
を開き、コードを編集してみましょう。
最初はReactのロゴが表示されているコードが書かれていますが、これを以下のように書き換えます。
import React from "react";
const App: React.FC = () => {
return (
<div style={{ textAlign: "center", padding: "20px" }}>
<h1>AIT カレンダーアプリ</h1>
<p>ここにカレンダーが表示されます</p>
</div>
);
};
export default App;
コードを保存すると、ブラウザの表示がリアルタイムに更新され、「AIT カレンダーアプリ」というタイトルと「ここにカレンダーが表示されます」というテキストに変わるはずです。

このように、開発サーバーはファイルの変更を監視しており、保存するたびに自動的にブラウザをリロード(または差分更新)してくれます。
これがReact開発の効率を高めるホットリロード機能です。
2. カレンダーアプリのコードを記述する
App.tsx
src/App.tsx
の内容を、提供していただいた以下のコードに置き換えてください。
import React, { useState, useEffect } from "react";
import "./App.css";
interface CalendarDay {
date: Date;
isCurrentMonth: boolean;
isToday: boolean;
}
const App: React.FC = () => {
const [currentDate, setCurrentDate] = useState(new Date());
const [calendar, setCalendar] = useState<CalendarDay[]>([]);
useEffect(() => {
console.log("月が変わりました:", currentDate);
generateCalendar();
}, [currentDate]);
const generateCalendar = () => {
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const startDay = firstDay.getDay(); // 日曜日 = 0
const today = new Date();
const days: CalendarDay[] = [];
// --- 前月の日付を追加(空白埋め)---
const prevMonthLastDate = new Date(year, month, 0).getDate();
for (let i = startDay - 1; i >= 0; i--) {
const date = new Date(year, month - 1, prevMonthLastDate - i);
days.push({
date,
isCurrentMonth: false,
isToday: false,
});
}
// --- 当月の日付を追加 ---
for (let i = 1; i <= lastDay.getDate(); i++) {
const date = new Date(year, month, i);
const isToday =
today.getFullYear() === date.getFullYear() &&
today.getMonth() === date.getMonth() &&
today.getDate() === date.getDate();
days.push({
date,
isCurrentMonth: true,
isToday,
});
}
// --- 翌月の空白(末尾を埋めて行を完成)---
const totalCells = days.length;
const nextFillCount = totalCells % 7 === 0 ? 0 : 7 - (totalCells % 7);
for (let i = 1; i <= nextFillCount; i++) {
const date = new Date(year, month + 1, i);
days.push({
date,
isCurrentMonth: false,
isToday: false,
});
}
setCalendar(days);
};
const goToPrevMonth = () => {
setCurrentDate(
new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1)
);
};
const goToNextMonth = () => {
setCurrentDate(
new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1)
);
};
console.log("現在の表示月:", currentDate);
return (
<div className="App">
<h1>カレンダーアプリ</h1>
<div className="calendar">
<div className="calendar-header">
<button onClick={goToPrevMonth}>{"<"}</button>
<h2>
{currentDate.getFullYear()}年{currentDate.getMonth() + 1}月
</h2>
<button onClick={goToNextMonth}>{">"}</button>
</div>
<div className="calendar-grid">
{["日", "月", "火", "水", "木", "金", "土"].map((d) => (
<div key={d} className="day-label">
{d}
</div>
))}
{calendar.map((day, idx) => (
<div
key={idx}
className={`date-cell ${day.isToday ? "today" : ""} ${
day.isCurrentMonth ? "" : "other-month"
}`}
>
{day.date.getDate()}
</div>
))}
</div>
</div>
</div>
);
};
export default App;
App.Css
そして、カレンダーの基本的なスタイルを設定するために、src/App.css
を以下の内容に置き換えてください。
.App {
text-align: center;
padding: 2rem;
font-family: sans-serif;
}
.calendar {
max-width: 600px;
margin: 0 auto;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.calendar-header button {
padding: 0.4rem 0.8rem;
font-size: 1rem;
}
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 4px;
}
.day-label,
.date-cell {
padding: 10px;
border: 1px solid #ccc;
}
.day-label {
font-weight: bold;
background-color: #f0f0f0;
}
.date-cell.other-month {
color: #aaa;
background-color: #f9f9f9;
}
.date-cell.today {
font-weight: bold;
border: 2px solid #007bff;
background-color: #e0f0ff;
}
作成したアプリの確認
コードを保存すると、ブラウザに現在の月のカレンダーが表示されているはずです。左右のボタンをクリックすると、月が移動するのを確認できます。

まとめ
Reactは、そのコンポーネントベースの設計や状態管理の仕組みを通じて、効率的で再利用性の高いUI開発を可能にします。
TypeScriptとの相性も抜群で、型安全な開発体験を実現できるのも大きな魅力の一つです。
今回ご紹介した基本を押さえておけば、Reactの導入もスムーズに進められるはず。
ぜひこの機会に、Reactを自分の開発スキルに取り入れてみてください!
コメント