Reactで簡単なアプリケーションを作成する
Reactを使って簡単なアプリケーションを作成したいと思います。
画面のイメージとしては、以下のような感じです。
ホームページ

ページ1

ページ2

ページ3

ちなみに管理人はReact初心者です。
Reactのバージョンの差異などが原因で解説サイトのサンプルコードが動作しなかったりして苦労したので、今後自分がReactアプリケーションを作成するときに参考になるように、備忘録としてここに残しておこうと思います。
間違いなどあれば、お気軽に連絡していただければと思います。
最終的なディレクトリ構造は以下のとおりです。
.
├── package-lock.json
├── package.json
├── src
│ ├── index.html
│ └── js
│ ├── App.js
│ ├── components
│ │ └── NavBar.js
│ ├── index.js
│ └── pages
│ ├── Home.js
│ ├── Page1.js
│ ├── Page2.js
│ └── Page3.js
└── webpack.config.js
管理人の開発環境は以下のとおりです。
- Windows 11
- Node.js v18.15.0
この記事の執筆にあたっては、以下のQiita記事を参考にしました。
プロジェクトの作成
自分はnpm init
してからnpm install --save-dev ...
で必要なパッケージをインストールしましたが、具体的なコマンドを忘れてしまったのと、新しくnpm install --save-dev ...
すると自分の環境とパッケージのバージョンが変わっていて動作しなくなったりしそうなので、自分の手元にあるpackage.jsonを共有します。
{
"name": "reactsample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack serve --mode development",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/preset-react": "^7.22.5",
"babel-loader": "^9.1.2",
"prettier": "^2.8.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^6.12.1",
"react-router-dom": "^6.12.1",
"webpack": "^5.86.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}
}
package.jsonを作成したら、npm install
を実行します。
必要なパッケージがnode_modulesディレクトリ配下に一通りインストールされるはずです。
webpack.config.js
webpack.config.jsはWebpackの設定ファイルです。
Webpackは複数のJavaScriptファイルを一つにまとめる(bundle)ツールです。
開発時にはページやコンポーネントごとにファイルを分けて開発しますが、Webpackを使うとそれらを一つにまとめることができます。
ファイルをまとめることによってブラウザからWebサーバーへのリクエスト数が減少し、パフォーマンスを改善することができます。
const debug=process.env.NODE_ENV!=="production";
const webpack=require("webpack");
const path=require("path");
module.exports={
context: path.join(__dirname,"src"),
entry: "./js/index.js",
module: {
rules: [{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: [{
loader: "babel-loader",
options: {
presets: ["@babel/preset-react","@babel/preset-env"]
}
}]
}]
},
output: {
path: __dirname+"/src/",
filename: "index.min.js",
publicPath: "/"
},
devServer: {
static: {
directory: path.join(__dirname,"src")
},
historyApiFallback: true
},
plugins: debug?[]:[
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({mangle:false,sourcemap:false})
]
}
src/index.html
トップページです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content="React sample application" />
<meta name="author" content="maeda6uiui" />
<title>React sample application</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous"
/>
</head>
<body>
<!--ここにReactで作成したコンポーネントを表示します-->
<div id="app"></div>
<script src="index.min.js"></script>
</body>
</html>
管理人にはCSSを作成する能力がないので、Bootstrapをそのまま使います。
src/js/index.js
ここがReactアプリケーションのエントリーポイントとなります。
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const app = document.getElementById("app");
const root = ReactDOM.createRoot(app);
root.render(<App />);
先に紹介したindex.htmlで、id="app"
をもつdiv要素がありました。
ここでは、そのdiv要素のところにReactで作成したコンポーネントを埋め込む処理を行っています。(たぶん)
実際のアプリケーションはApp.jsで実装していきます。
src/js/App.js
実際のアプリケーションの中身です。
ここではルーティングの設定を行っています。
たとえば、/page-1にアクセスされた場合にはPage1コンポーネントを表示する、といった流れです。
各コンポーネントの具体的な中身はそれぞれ別のファイルで定義しています。
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Page1 from "./pages/Page1";
import Page2 from "./pages/Page2";
import Page3 from "./pages/Page3";
const App = () => {
return (
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/page-1" element={<Page1 />} />
<Route path="/page-2" element={<Page2 />} />
<Route path="/page-3" element={<Page3 />} />
</Routes>
</Router>
);
};
export default App;
src/js/components/NavBar.js
画面上部に表示されるナビゲーションバーです。
import React from "react";
import { Link } from "react-router-dom";
const NavBar = () => {
return (
<nav className="navbar navbar-expand-md navbar-light bg-light">
<div className="container-fluid">
<Link to="/" className="navbar-brand">
Reactサンプル
</Link>
<ul className="navbar-nav me-auto">
<li className="nav-item">
<Link to="/page-1" className="nav-link">
ページ1
</Link>
</li>
<li className="nav-item">
<Link to="/page-2" className="nav-link">
ページ2
</Link>
</li>
<li className="nav-item">
<Link to="/page-3" className="nav-link">
ページ3
</Link>
</li>
</ul>
<ul className="navbar-nav ms-auto">
<li className="nav-item">
<Link to="https://www.google.com/" className="nav-link">
退出する
</Link>
</li>
</ul>
</div>
</nav>
);
};
export default NavBar;
src/js/pages/Home.js
ホームページです。
import React from "react";
import NavBar from "../components/NavBar";
const Home = () => {
return (
<div>
<NavBar />
<div className="container-fluid">
<h1>ようこそ!</h1>
<p>Reactを用いたサンプルアプリケーションです。</p>
</div>
</div>
);
};
export default Home;
src/js/pages/Page1.js
一つ目のページです。
import React from "react";
import NavBar from "../components/NavBar";
const Page1 = () => {
return (
<div>
<NavBar />
<div className="container-fluid">
<h1>ページ1</h1>
<p>一つ目のページです。</p>
</div>
</div>
);
};
export default Page1;
src/js/pages/Page2.js
二つ目のページです。
チェックボックスのチェック状態によってナビゲーションバーの表示・非表示を切り替えています。
import React, { useState } from "react";
import NavBar from "../components/NavBar";
const Page2 = () => {
const [checked, setChecked] = useState(true);
return (
<div>
{checked ? <NavBar /> : undefined}
<div className="container-fluid">
<h1>ページ2</h1>
<p>二つ目のページです。</p>
<div className="form-check">
<input
className="form-check-input"
type="checkbox"
value=""
id="shouldShowNavBarCheckbox"
checked={checked}
onChange={() => setChecked((prevState) => !prevState)}
/>
<label
className="form-check-label"
htmlFor="shouldShowNavBarCheckbox"
>
ナビゲーションバーを表示する
</label>
</div>
</div>
</div>
);
};
export default Page2;
src/js/pages/Page3.js
三つ目のページです。
テキストを入力してOKボタンを押すと、アラートが表示されます。
import React, { useState } from "react";
import { Link } from "react-router-dom";
import NavBar from "../components/NavBar";
const Page3 = () => {
const [text, setText] = useState("");
return (
<div>
<NavBar />
<div className="container-fluid">
<h1>ページ3</h1>
<p>三つ目のページです。</p>
<div className="mb-3">
<label className="form-label" htmlFor="myRandomTextarea">
適当に作ったテキストエリア
</label>
<textarea
className="form-control"
id="myRandomTextarea"
rows="3"
placeholder="Hello, world!"
value={text}
onChange={(e) => setText(e.target.value)}
/>
</div>
<div className="row justify-content-md-end">
<div className="col-md-auto">
<Link to="/" className="btn btn-secondary">
キャンセル
</Link>
</div>
<div className="col-md-auto">
<button
className={
text === "" ? "btn btn-primary disabled" : "btn btn-primary"
}
onClick={() => alert(text)}
>
OK
</button>
</div>
</div>
</div>
</div>
);
};
export default Page3;
アプリケーションの実行
npm start
で開発サーバーを起動します。
ここで実際に実行されているコマンドは、package.jsonに記載しているwebpack serve --mode development
です。
デフォルトの設定では、localhost:8080でページにアクセスできるはずです。