概要
- Reactアプリケーションで、データ可視化や分析ダッシュボードを作成する際に利用される
Rechartsライブラリを紹介 -
LineChartやBarChartなどのコンポーネントを用いて、シンプルかつ拡張可能なチャート描画を実現 - プロジェクトの規模や目的に応じて、ディレクトリ構成や**責務分離(FE/BE/DB)**をどう設計するかが重要
Rechartsを導入することで 「データを視覚的に理解しやすい形で提示する」 Reactアプリを効率的に作成できる
実施条件
- React + TypeScript プロジェクトが構築済みであること
- APIとの通信(
axiosなど)に関する基礎知識があること - データの保存方法(DB利用 or 直接API呼び出し)を理解していること
環境
| ツール | バージョン | 目的 |
|---|---|---|
| Node.js | 22.5.1 | Reactアプリ実行環境 |
| React | 19.1.0 | UI構築 |
| TypeScript | 4.9 | 型定義による安全な開発 |
| Recharts | 2.15.4 | データ可視化ライブラリ |
ディレクトリ構成
Rechartsを使ったReactプロジェクトは、データの流れ方によって3つの構成パターンに分類できる。
パターン①:保存型(FE + BE + DB)
履歴分析や安定性が必要な場合、バックエンドとデータベースを組み合わせてチャートに描画。
project-root/
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ └── CryptoChart.tsx
│ │ ├── services/
│ │ │ └── api.ts
│ │ └── pages/
│ │ └── Dashboard.tsx
├── backend/
│ ├── routes/
│ │ └── cryptoRoutes.js
│ ├── controllers/
│ │ └── cryptoController.js
│ ├── services/
│ │ └── coingeckoService.js
│ └── models/
│ └── CryptoPrice.js
├── database/
│ └── schema.sql
データフロー
パターン①:保存型(FE + BE + DB)
データの流れ(クライアント入力データ)
データの流れ(外部APIデータ)
コード
frontend/
services/api.ts
バックエンドAPIにリクエストしてデータを取得する。
services/api.ts
import axios from 'axios';
export const fetchCryptoPrices = async () => {
const res = await axios.get('/api/crypto/prices'); // BEのエンドポイント
return res.data; // { timestamp, coin, price }
};
components/CryptoChart.tsx
Rechartsを使ったラインチャート描画。
components/CryptoChart.tsx
import { LineChart, Line, XAxis, YAxis, Tooltip } from 'recharts';
export default function CryptoChart({
data,
}: {
data: { timestamp: string; price: number }[];
}) {
return (
<LineChart width={600} height={300} data={data}>
<XAxis dataKey="timestamp" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="price" stroke="#82ca9d" />
</LineChart>
);
}
pages/Dashboard.tsx
バックエンドからデータを取得してチャートに渡す。
pages/Dashboard.tsx
import { useEffect, useState } from 'react';
import { fetchCryptoPrices } from '../services/api';
import CryptoChart from '../components/CryptoChart';
export default function Dashboard() {
const [data, setData] = useState<{ timestamp: string; price: number }[]>([]);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetchCryptoPrices();
setData([{ timestamp: res.timestamp, price: res.price }]);
} catch (error) {
console.error('Failed to fetch crypto prices:', error);
}
};
fetchData();
}, []);
return (
<div style={{ padding: '1rem' }}>
<h2>Crypto Price Dashboard</h2>
<CryptoChart data={data} />
</div>
);
}
backend/
routes/cryptoRoutes.js
エンドポイント定義。
routes/cryptoRoutes.js
// routes/cryptoRoutes.js
import express from 'express';
import { getLatestPrice } from '../controllers/cryptoController.js';
const router = express.Router();
router.get('/prices', getLatestPrice); // この /prices がフロントの /api/crypto/prices にマッピング
export default router;
controllers/cryptoController.js
APIコールとDB保存を行い、フロントに返すロジック。
controllers/cryptoController.js
import { CryptoPrice } from '../models/CryptoPrice.js';
import { fetchPriceFromAPI } from '../services/coingeckoService.js';
// 外部APIのデータをDBに保存して返す
export const getLatestPrice = async (req, res) => {
try {
const coin = req.query.coin || 'bitcoin';
const currency = req.query.currency || 'usd';
// 1. 外部APIから最新価格を取得
const apiData = await fetchPriceFromAPI(coin, currency);
const price = apiData[coin][currency];
// 2. DBに保存
const record = await CryptoPrice.create({
timestamp: new Date(),
coin,
price,
});
// 3. フロントに返却
res.json({
timestamp: record.timestamp,
coin: record.coin,
price: record.price,
});
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Failed to fetch price' });
}
};
services/coingeckoService.js
外部APIから仮想通貨価格を取得するロジック。
services/coingeckoService.js
import axios from 'axios';
export const fetchPriceFromAPI = async (coin = 'bitcoin', currency = 'usd') => {
const res = await axios.get(
`https://api.coingecko.com/api/v3/simple/price?ids=${coin}&vs_currencies=${currency}`
);
return res.data; // { bitcoin: { usd: 12345 } }
};
models/CryptoPrice.js
DBモデル(例:SequelizeやPrismaで定義)。
models/CryptoPrice.js
// Sequelizeの例
import { DataTypes } from 'sequelize';
import { sequelize } from '../db'; // DB接続済みのインスタンス
export const CryptoPrice = sequelize.define('CryptoPrice', {
timestamp: {
type: DataTypes.DATE,
allowNull: false,
},
coin: {
type: DataTypes.STRING,
allowNull: false,
},
price: {
type: DataTypes.FLOAT,
allowNull: false,
},
});
ディレクトリ設計まとめ
| パターン | 特徴 | 適用例 |
|---|---|---|
| 保存型 | 履歴分析・安定性あり | ダッシュボード、統計分析 |
| リアルタイム型 | 即時性・軽量 | トレンド表示、速報性重視アプリ |
| 直接呼び出し型 | 最速・最小構成 | プロトタイプ、個人利用ツール |