環境の準備
mkdir <ファイル名>
cd <ファイル名>
npm init -y //package.jsonファイルを作成
npm i express mysql2 sequelize cors
npm i --save-dev nodemon
//新しいtarminalを作成する
npx create-react-app <ファイル名>
cd <ファイル名>
npm i react-router-dom axios bulma
コンポーネント・ファイル構成
backend
├─ config
└── Database.js
├─ controllers
└── UserController.js
└── models
└── UserModel.js
frontend
├─ src
├─ components
├── AddUser.jsx
├── EditList.jsx
└── UserList.jsx
├── App.tsx
└── index.tsx
backend/config/Database.js
import { Sequelize } from 'sequelize';
const db = new Sequelize('crud_db', 'root', '', {
host: 'localhost',
dialect: 'mysql',
});
export default db;
backend/controllers/UserController.js
import User from '../models/UserModel';
export const getUsers = async (req, res) => {
try {
const response = await User.findAll();
res.status(200).json(response);
} catch (error) {
console.log(error.message);
}
};
export const getUserById = async (req, res) => {
try {
const response = await User.findOne({
where: {
id: req.params.id,
},
});
res.status(200).json(response);
} catch (error) {
console.log(error.message);
}
};
export const createUser = async (req, res) => {
try {
await User.create(req.body);
res.status(201).json({ msg: 'User Created' });
} catch (error) {
console.log(error.message);
}
};
export const updateUser = async (req, res) => {
try {
await User.update(req.body, {
where: {
id: req.params.id,
},
});
res.status(200).json({ msg: 'User Updated' });
} catch (error) {
console.log(error.message);
}
};
export const deleteUser = async (req, res) => {
try {
await User.destroy(req.body, {
where: {
id: req.params.id,
},
});
res.status(200).json({ msg: 'User Deleted' });
} catch (error) {
console.log(error.message);
}
};
backend/models/UserModel.js
import { Sequelize } from 'sequelize';
import db from '../config/Database';
const { DataTypes } = Sequelize;
const User = db.define(
'users',
{
name: DataTypes.STRING,
email: DataTypes.STRING,
gender: DataTypes.STRING,
},
{
freezeTableName: true,
}
);
export default User;
(async () => {
await db.sync();
})();
frontend/ src/ components/ AddUser.jsx
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
const AddUser = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [gender, setGender] = useState('Male');
const navigate = useNavigate();
const saveUser = async (e) => {
e.preventDefault();
try {
await axios.post('http://localhost:5000/users', { name, email, gender });
navigate('/');
} catch (error) {
console.log(error);
}
};
return (
<div className='mt-5 columns is-centered'>
<div className='column is-half'>
<form onSubmit={saveUser}>
<div className='field'>
<label className='label'>Name</label>
<div className='control'>
<input
type='text'
className='input'
value={name}
onChange={(e) => setName(e.target.value)}
placeholder='Name'
/>
</div>
</div>
<div className='field'>
<label className='label'>Email</label>
<div className='control'>
<input
type='text'
className='input'
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder='Email'
/>
</div>
</div>
<div className='field'>
<label className='label'>Gender</label>
<div className='control'>
<div className='select is-fullwidth'>
<select
value={gender}
onChange={(e) => setGender(e.target.value)}
>
<option value='Male'>Male</option>
<option value='Female'>Female</option>
</select>
</div>
</div>
</div>
<div className='field'>
<button type='submit' className='button is-success'>
Save
</button>
</div>
</form>
</div>
</div>
);
};
export default AddUser;
frontend/ src/ components/ EditList.jsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useNavigate, useParams } from 'react-router-dom';
const EditUser = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [gender, setGender] = useState('Male');
const navigate = useNavigate();
const { id } = useParams();
useEffect(() => {
getUserById();
}, []);
const updateUser = async (e) => {
e.preventDefault();
try {
await axios.patch(`http://localhost:5000/users/${id}`, {
name,
email,
gender,
});
navigate('/');
} catch (error) {
console.log(error);
}
};
const getUserById = async () => {
const response = await axios.get(`http://localhost:5000/users/${id}`);
setName(response.data.name);
setEmail(response.data.email);
setGender(response.data.gender);
};
return (
<div className='mt-5 columns is-centered'>
<div className='column is-half'>
<form onSubmit={updateUser}>
<div className='field'>
<label className='label'>Name</label>
<div className='control'>
<input
type='text'
className='input'
value={name}
onChange={(e) => setName(e.target.value)}
placeholder='Name'
/>
</div>
</div>
<div className='field'>
<label className='label'>Email</label>
<div className='control'>
<input
type='text'
className='input'
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder='Email'
/>
</div>
</div>
<div className='field'>
<label className='label'>Gender</label>
<div className='control'>
<div className='select is-fullwidth'>
<select
value={gender}
onChange={(e) => setGender(e.target.value)}
>
<option value='Male'>Male</option>
<option value='Female'>Female</option>
</select>
</div>
</div>
</div>
<div className='field'>
<button type='submit' className='button is-success'>
Updata
</button>
</div>
</form>
</div>
</div>
);
};
export default EditUser;
frontend/ src/ components/ UserList.jsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
const UserList = () => {
const [users, setUser] = useState([]);
useEffect(() => {
getUsers();
}, []);
const getUsers = async () => {
const response = await axios.get('http://localhost:5000/users');
setUser(response.data);
};
const deleteUser = async (id) => {
try {
await axios.delete(`http://localhost:5000/users/${id}`);
getUsers();
} catch (error) {
console.log(error);
}
};
return (
<div className='mt-5 columns is-centered'>
<div className='column is-half'>
<Link to={`add`} className='button is-success'>
Add New
</Link>
<table className='table is-striped is-fullwidth'>
<thead>
<tr>
<th>No</th>
<th>Name</th>
<th>Email</th>
<th>Gender</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{users.map((user, index) => (
<tr key={user.id}>
<td>{index + 1}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
<td>
<Link
to={`edit/${user.id}`}
className='button is-small is-info'
>
Edit
</Link>
<button
onClick={() => deleteUser(user.id)}
className='button is-small is-danger'
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};
export default UserList;
frontend/ src/ App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import AddUser from './components/AddUser';
import UserList from './components/UserList';
import EditUser from './components/EditUser';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<UserList />} />
<Route path='add' element={<AddUser />} />
<Route path='edit/:id' element={<EditUser />} />
</Routes>
</BrowserRouter>
);
}
export default App;
frontend/ src/ index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import 'bulma/css/bulma.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
参考サイト
Tutorial LENGKAP CRUD dengan Node JS, Express, React JS, dan MySQL (Full Stack)