
JSXの書き方:React開発の第一歩
JSX(JavaScript XML)はReactの核となる構文で、JavaScript内にHTMLのようなマークアップを直接記述できるようにします。これにより […]
この演習では、Reactの基礎を学んだばかりの方向けに2つのアプリケーション開発を通じて実践的なスキルを身につけます。最初にState管理を学ぶToDoアプリ、次にAPI連携を学ぶ天気アプリを作成します。
npx create-react-app todo-app
cd todo-app
npm start
src/App.js
を以下のように編集します:
import React from 'react';
import './App.css';
function App() {
return (
<div className="app">
<h1>ToDoアプリ</h1>
{/* ここにToDoフォームとリストを追加 */}
</div>
);
}
export default App;
Appコンポーネント内でuseStateを使ってToDoリストを管理します。
import React, { useState } from 'react';
function App() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
// ここに関数を追加していきます
return (
// ...
);
}
以下の関数をAppコンポーネント内に追加してください:
const addTodo = () => {
if (inputValue.trim()) {
setTodos([...todos, { text: inputValue, completed: false }]);
setInputValue('');
}
};
return文内に以下のJSXを追加:
<div className="todo-form">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="新しいToDoを入力"
/>
<button onClick={addTodo}>追加</button>
</div>
以下のJSXを追加:
<ul className="todo-list">
{todos.map((todo, index) => (
<li key={index}>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
</li>
))}
</ul>
最終的なApp.jsは以下のようになります:
import React, { useState } from 'react';
import './App.css';
function App() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
const addTodo = () => {
if (inputValue.trim()) {
setTodos([...todos, { text: inputValue, completed: false }]);
setInputValue('');
}
};
const toggleTodo = (index) => {
const newTodos = [...todos];
newTodos[index].completed = !newTodos[index].completed;
setTodos(newTodos);
};
return (
<div className="app">
<h1>ToDoアプリ</h1>
<div className="todo-form">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="新しいToDoを入力"
/>
<button onClick={addTodo}>追加</button>
</div>
<ul className="todo-list">
{todos.map((todo, index) => (
<li key={index} onClick={() => toggleTodo(index)}>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
</li>
))}
</ul>
</div>
);
}
export default App;
src/App.css
に以下のスタイルを追加:
.app {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.todo-form {
display: flex;
margin-bottom: 20px;
}
.todo-form input {
flex-grow: 1;
padding: 8px;
font-size: 16px;
}
.todo-form button {
padding: 8px 16px;
margin-left: 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
}
.todo-list {
list-style: none;
padding: 0;
}
.todo-list li {
padding: 10px;
margin-bottom: 5px;
background-color: #f5f5f5;
cursor: pointer;
}
.todo-list li:hover {
background-color: #e9e9e9;
}
npx create-react-app weather-app
cd weather-app
npm start
npm install axios
src/App.js
を以下のように編集:
import React, { useState } from 'react';
import axios from 'axios';
import './App.css';
function App() {
const [city, setCity] = useState('');
const [weather, setWeather] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
// ここに関数を追加していきます
return (
<div className="app">
<h1>天気予報アプリ</h1>
{/* ここに検索フォームと天気表示を追加 */}
</div>
);
}
export default App;
OpenWeatherMap APIを使用します(無料で利用可能)。まずはAPIキーを取得してください:
以下の関数をAppコンポーネント内に追加:
const fetchWeather = async () => {
if (!city) return;
setLoading(true);
setError('');
try {
const response = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_API_KEY&units=metric&lang=ja`
);
setWeather(response.data);
} catch (err) {
setError('都市が見つかりませんでした');
setWeather(null);
} finally {
setLoading(false);
}
};
return文内に以下のJSXを追加:
<div className="search-form">
<input
type="text"
value={city}
onChange={(e) => setCity(e.target.value)}
placeholder="都市名を入力(例: Tokyo)"
/>
<button onClick={fetchWeather} disabled={loading}>
{loading ? '取得中...' : '天気を取得'}
</button>
</div>
以下のJSXを追加:
{error && <div className="error">{error}</div>}
{weather && (
<div className="weather-card">
<h2>{weather.name}の天気</h2>
<div className="weather-info">
<img
src={`http://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`}
alt={weather.weather[0].description}
/>
<p>{weather.weather[0].description}</p>
<p>気温: {weather.main.temp}°C</p>
<p>湿度: {weather.main.humidity}%</p>
<p>風速: {weather.wind.speed}m/s</p>
</div>
</div>
)}
最終的なApp.jsは以下のようになります:
import React, { useState } from 'react';
import axios from 'axios';
import './App.css';
function App() {
const [city, setCity] = useState('');
const [weather, setWeather] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const fetchWeather = async () => {
if (!city) return;
setLoading(true);
setError('');
try {
const response = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_API_KEY&units=metric&lang=ja`
);
setWeather(response.data);
} catch (err) {
setError('都市が見つかりませんでした');
setWeather(null);
} finally {
setLoading(false);
}
};
return (
<div className="app">
<h1>天気予報アプリ</h1>
<div className="search-form">
<input
type="text"
value={city}
onChange={(e) => setCity(e.target.value)}
placeholder="都市名を入力(例: Tokyo)"
/>
<button onClick={fetchWeather} disabled={loading}>
{loading ? '取得中...' : '天気を取得'}
</button>
</div>
{error && <div className="error">{error}</div>}
{weather && (
<div className="weather-card">
<h2>{weather.name}の天気</h2>
<div className="weather-info">
<img
src={`http://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`}
alt={weather.weather[0].description}
/>
<p>{weather.weather[0].description}</p>
<p>気温: {weather.main.temp}°C</p>
<p>湿度: {weather.main.humidity}%</p>
<p>風速: {weather.wind.speed}m/s</p>
</div>
</div>
)}
</div>
);
}
export default App;
src/App.css
に以下のスタイルを追加:
.app {
max-width: 500px;
margin: 0 auto;
padding: 20px;
text-align: center;
}
.search-form {
display: flex;
margin-bottom: 20px;
}
.search-form input {
flex-grow: 1;
padding: 10px;
font-size: 16px;
}
.search-form button {
padding: 10px 20px;
margin-left: 10px;
background-color: #2196F3;
color: white;
border: none;
cursor: pointer;
}
.search-form button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.error {
color: #f44336;
margin-bottom: 20px;
}
.weather-card {
background-color: #f5f5f5;
padding: 20px;
border-radius: 8px;
}
.weather-info img {
width: 100px;
height: 100px;
}
.weather-info p {
margin: 10px 0;
font-size: 18px;
}
この演習を通じて、Reactの基本的な概念である状態管理(useState)、副作用処理(useEffect)、コンポーネントのライフサイクル、外部APIとの連携方法などを実践的に学ぶことができました。ToDoアプリではReactの基本的なデータフローを、天気アプリでは非同期処理と外部リソースの活用方法を理解することが目的でした。
さらに学びを深めたい場合は、Reactの公式ドキュメントや、より複雑なプロジェクトに挑戦してみてください。