とほほの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/ (旧サイト)