とほほのReact入門
- React とは
- インストールとアプリケーション作成と実行
- コンポーネントを定義する
- サブコンポーネントを定義する
- プロパティを渡す
- JSX の書き方
- CSSファイルを読み込む
- リストを表示する
- ステータスを変更する
- ルーティングでページを切り替える
- ユーザ管理画面サンプル
- リンク
React とは
- SPA(Single-Page Application) を実現する JavaScript フレームワークの一つです。
- Angular, Vue.js とよく比較されます。
- Meta社(旧:Facebook社)によって開発され、X(旧:Facebook) の Web サイトでも利用されています。
- 2025年9月現在の最新バージョンは 19.1.1 です。
- 2020年頃のバージョン 16 当時の記事は こちら にあります。
- MITライセンスで公開されており、商用利用可能です。
- JavaScript の中に直接 HTML/XML を記述する JSX という技術を利用しています。
- JavaScript は ES6 の文法である import やアロー関数を取り入れています。
- JSX や TypeScript の文法を、トランスパイラで JavaScript に変換しています。
- Chrome, Safari, Firefox などで動作します。IE のサポートは終了しています。
インストールとアプリケーション作成と実行
下記環境でのインストール方法を説明します。以前は create-react-app を用いた構築が主流でしたが、現在 create-react-app は非推奨となり、代わりに Vite などを用いた方法が推奨されています。
OS : AlmaLinux 10.0 Node.js: v22.16.0 npm : 10.9.2 Vite : 7.1.6 React : 19.1.1
Node.js をインストールします。
# dnf -y install nodejs # node --version v22.16.0 # npm --version 10.9.2
Vite をインストールし、テンプレートとして React アプリケーション環境を構築します。
$ npm create vite@7.1 my-app -- --template react
アプリケーション環境に移動し、必要なパッケージをインストールします。
$ cd my-app $ npm install
簡易サーバーを起動します。表示される http:// アドレスにブラウザでアクセスして Vite + React の画面が表示されれば成功です。
$ npm run dev VITE v7.1.6 ready in 301 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help
ホスト名やポート番号を変更したい場合は vite.config.js ファイルに下記の様に追加してください。
export default defineConfig({
plugins: [react()],
server: {
host: "0.0.0.0",
port: 3000,
strictPort: true,
},
})
src/App.jsx を次のように書き換えてみましょう。npm run dev を別コンソールで起動したままにしておけば、プログラムを更新した時点で自動的にブラウザが再ロードします。
export default function App() {
return <h1>Hello, world!</h1>;
}
ブラウザからアクセスして "Hello, world!" が表示されれば成功です。
コンポーネントを定義する
コンポーネントの定義は様々な方法があります。React 15.5 より古いバージョンでは、React.createClass() を用いて定義していましたが、React 15.5 で廃止されました。
var App = React.createClass({ // 廃止
render() {
return <h1>Hello!</h1>;
}
});
createReactClass() を利用する方法もありました。npm で create-react-class をインストールしておく必要があります。しかし、この書き方も今では非推奨となっており、あまり用いられていません。
var createReactClass = require('create-react-class');
var App = createReactClass({
render: function() {
return <h1>Hello!</h1>;
}
});
React 15.0 からは、ES6 のクラスを用いて定義する方法が主流となりました。
class App extends React.Component {
render() {
return <h1>Hello!</h1>;
}
}
React 16.8 以降では、関数を用いて定義する方法が主流となりました。関数では元々ステータスを保持することができませんでしたが、React 16.8 でサポートされた Hooks を用いることで、関数でもステータスを制御することが可能となりました。現在推奨されているのはこの方法です。
export default function App() {
return <h1>Hello!</h1>;
}
サブコンポーネントを定義する
App コンポーネントから Hello サブコンポーネントを呼び出してみましょう。
export default function Hello() {
return <h1>Hello!</h1>;
}
import Hello from './Hello';
export default function App() {
return <Hello></Hello>;
}
ブラウザからアクセスして Hello! が表示されれば成功です。
プロパティを渡す
下記の様にして、コンポーネントにプロパティを渡すことができます。
import Hello from './Hello';
export default function App() {
return <Hello name="Tanaka"></Hello>;
}
コンポーネント側はこれを引数 props 引数で受け取ります。
export default function Hello(props) {
return <h1>Hello {props.name}!</h1>;
}
ブラウザからアクセスして Hello Tanaka! が表示されれば成功です。
JSX の書き方
React では、JavaScript の文法中に XML ライクなタグを記述可能な、JavaScript の拡張言語 JSX を採用しています。
return <h1>Hello!</h1>;
( ... ) で囲むことにより、複数行のタグを記述することができます。
return (
<div>
<h1>Hello!</h1>
<p>This is ...</p>
</div>
);
JSX 構文では、要素は単一の要素として記述する必要があります。下記の例は、2つの要素を返却しているためエラーとなります。
return (
<h1>Hello!</h1>
<p>This is ...</p> // Error!
);
下記の様に無名要素 <>...</> を用いてひとつの要素にすることもできます。
return (
<>
<h1>Hello!</h1>
<p>This is ...</p>
</>
);
{ 変数名 } で変数の値を参照することができます。
const name = 'Tanaka';
return <h1>Hello {name}!</h1>
{ 変数名 } は属性値として使用することもできます。
const name = 'Tanaka';
return <h1 title={name}>Hello!</h1>
{ ... } の中では JavaScript の式を記述することができます。
return <h1>3 + 5 = { 3 + 5 }</h1>;
{ ... } の中から関数を呼び出すこともできます。
function add(x, y) { return x + y; }
export default function Hello(props) {
return <h1>3 + 5 = { add(3, 5) }</h1>;
}
{ ... } の中で複文を記述することはできません。下記はエラーとなります。
return <h1>3 + 5 = {a = 3; b = 5; a + b}</h1>; // Error!
コメントは {/* ... */} で囲みます。
{/* コメント... */}
return <h1>Hello!</h1>;
class を指定する際は、class の代わりに className を指定します。
return <h1 className="my-class">Hello!</h1>;
style を指定する際は、{ ... } の中に JSON で記述します。デリミタはセミコロン(;)ではなくカンマ(,)、値は文字列として指定、font-size などのハイフン(-)を用いるプロパティ名はスネークケースではなく、fontSize などのキャメルケースで指定します。
return <h1 style={{color:'red', fontSize:'64pt'}}>Hello!</h1>;
イベントハンドラを指定するには、下記の様に記述します。
return <h1 onClick={(e) => {console.log(e)}}>Hello!</h1>;
CSSファイルを読み込む
CSS ファイルも import で読み込むことができます。
h1 { color: red; }
import './Hello.css';
export default function Hello() {
return <h1>Hello!</h1>;
}
リストを表示する
下記の例では、users 配列に対して map() を適用し、リストを表示しています。React が配列要素の変更を検出しやすくするために、配列要素には一意キーを持つ key 属性を指定します。
export default function Hello() {
const users = [
{ name: "Tanaka", age: 26 },
{ name: "Suzuki", age: 32 },
{ name: "Yamada", age: 43 },
];
const userList = users.map((user, index) =>
<li key={index}>{user.name}({user.age})</li>
);
return <ul>{userList}</ul>;
}
ステータスを変更する
useState()でステートを作成・変更する
画面上の変数をダイナミックに変更するには、useState() を用います。useState() は変数の値とその変数を動的に変更するための関数を返します。
import { useState } from 'react';
export default function Hello() {
const [message, setMessage] = useState("Hello!");
return (
<>
<h1>{message}</h1>
<button onClick={()=>setMessage("Bye!")}>Click!</button>
</>
);
}
リストを変更するには、users のプロパティに対して直接 push() や pop() するのではなく、React にプロパティの変更を認識させるために、一度リストのコピーを作成し、useXxxx() で値を置き換えます。
import { useState } from 'react';
export default function Hello() {
const [users, setUsers] = useState([
{ id: 1, name: "Tanaka" },
{ id: 2, name: "Suzuki" },
{ id: 3, name: "Yamada" },
]);
return (
<>
<ul>
{users.map(user => (<li key={user.id}>{user.name}</li>))}
</ul>
<button onClick={()=>{ setUsers([...users, { id: 4, name: "Kimura" }]); }}>Add</button>
<button onClick={()=>{ setUsers(users.filter(user => user.id !== 4)); }}>Delete</button>
</>
);
}
useState() と setState()
React 16 の頃のクラスコンポーネントでは下記の様に this.state と this.setState() を用いてステータスを管理していましたが、現在では React 16.8 でサポートされた useState() を使用することが推奨されています。
import React from 'react';
export default class Hello extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hello!' }; // 古い書き方
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
<button onClick={() => this.setState({message: 'Bye!'})}>Click!</button> // 古い書き方
</div>
);
}
}
ルーティングでページを切り替える
React Router をインストールする
URL に応じて、表示するコンポーネントを切り替えるにはルーティングを使用します。まず、react-router-dom をインストールします。
$ npm install react-router-dom
Link と Router でルーティングを振り分ける
プログラムを下記の様に修正してください。<Link> と <Router> は同じ <BrowserRouter> の子孫である必要があります。<Link> をメニュー、<Router> をページと考えれば、メニューによってページを切り替える SPA を実現することが可能となります。
import { BrowserRouter, Link, Routes, Route } from 'react-router-dom';
function HelloA() { return <h1>HelloA</h1>; }
function HelloB() { return <h1>HelloB</h1>; }
export default function Hello() {
return (
<BrowserRouter>
<ul>
<li><Link to="/hello-a">HelloA</Link></li>
<li><Link to="/hello-b">HelloB</Link></li>
</ul>
<Routes>
<Route path="/hello-a" element={<HelloA />} />
<Route path="/hello-b" element={<HelloB />} />
</Routes>
</BrowserRouter>
);
}
React Router v5 と v6 の差異
React Router v5 から v6 で下記の仕様が変わりました。
<Route component="...">の代わりに<Route element="...">を使用する。<Route path="...">は前方一致ではなく完全一致となり、exactは不要となった。- v6 で前方一致を表現したい時は
path="/*"の様にアスタリスク(*)を用いる。 <Switch>は使用しない。代わりに<Routes>を使用する。<BrowserRouter>配下に複数の要素を記述できるようになった。
ユーザ管理画面サンプル
最後に、Angular入門 のチュートリアルでも紹介したような、簡単なユーザ管理画面のサンプルを掲載します。
export default function Header() {
return <div className="header">React Sample Console</div>;
}
import { Link } from 'react-router-dom';
export default function Menu() {
return (
<ul className="menu">
<li><Link to="/dashboard">Dashboard</Link></li>
<li><Link to="/users">Users</Link></li>
</ul>
);
}
export default function Dashboard() {
return <h1>Dashboard</h1>;
}
import React, { useState } from 'react';
export default function Users() {
const [users, setUsers] = useState([
{ id: 1, name: "Yamada", age: 26 },
{ id: 2, name: "Tanaka", age: 32 },
{ id: 3, name: "Suzuki", age: 43 },
]);
const [form, setForm] = useState({ name: '', age: '' });
const [editingIndex, setEditingIndex] = useState(null);
const onChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const onSubmit = (e) => {
e.preventDefault();
if (editingIndex !== null) {
const updated = [...users];
updated[editingIndex] = form;
setUsers(updated);
setEditingIndex(null);
} else {
const maxId = Math.max(...users.map(user => user.id)) + 1;
const updated = [...users, { id: maxId, name: form.name, age: form.age}]
setUsers(updated);
}
setForm({ name: '', age: '' });
};
const onEdit = (index) => {
setForm(users[index]);
setEditingIndex(index);
};
const onDelete = (index) => {
setUsers(users.filter((_, i) => i !== index));
};
return (
<div>
<h1>Users</h1>
<form onSubmit={onSubmit}>
<input
type="text"
name="name"
value={form.name}
onChange={onChange}
placeholder="Name"
required
/>
<input
type="text"
name="age"
value={form.age}
onChange={onChange}
placeholder="Age"
required
/>
<button type="submit">{editingIndex !== null ? 'Update' : 'Add'}</button>
</form>
<table>
<thead>
<tr><th>ID</th><th>Name</th><th>Age</th><th>Edit</th><th>Delete</th></tr>
</thead>
<tbody>
{users.map((user, index) => (
<tr key={index}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.age}</td>
<td><button onClick={() => onEdit(index)}>Edit</button></td>
<td><button onClick={() => onDelete(index)}>Delete</button></td>
</tr>
))}
</tbody>
</table>
</div>
);
}
import './App.css';
import Header from './Header';
import Menu from './Menu';
import Dashboard from './Dashboard';
import Users from './Users';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
export default function App() {
return (
<BrowserRouter>
<Header />
<Menu />
<div className="main">
<Routes>
<Route path="/dashboard" element={ <Dashboard /> } />
<Route path="/users" element={ <Users /> } />
<Route path="/*" element={ <Dashboard /> } />
</Routes>
</div>
</BrowserRouter>
);
}
* {
margin: 0;
padding: 0;
color: #333;
box-sizing: border-box;
}
.header {
padding: 8px;
background-color: #000;
color: #fff;
font-weight: bold;
}
.menu {
padding: 4px;
background-color: #ddd;
li {
display: inline-block;
margin: 0 8px;
}
}
.main {
padding: 8px;
}
input[type="text"] {
width: 190px;
height: 30px;
line-height: 30px;
margin: 4px 8px 8px 0;
padding: 0 4px;
border: 1px solid #ccc;
border-radius: 4px;
outline: none;
&:focus {
border: 2px solid #888;
}
}
table {
border-collapse: collapse;
th, td {
padding: 4px 8px;
border: 1px solid #ccc;
}
th {
background-color: #eee;
}
}
button {
height: 30px;
min-width: 100px;
border: 1px solid #ccc;
border-radius: 4px;
}
/* 中身を空にする */
リンク
- https://react.dev/ (英語版)
- https://ja.react.dev/ (日本語版)
- https://reactjs.org/ (旧サイト)