React(Node js + MySQL)の構成でアプリを作成をしました【簡単なCRUDアプリケーション】

## 環境の準備

```
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)](https://www.youtube.com/watch?v=es9_6RFR7wk&t=465s)