React + CodeIgniter4 環境構築-バックエンドとフロントエンドを切り分ける②

#### この記事の前に
この記事はpart2です、part1は下記リンクになります。

https://qiita.com/begginer-info-base/items/b51c3dbd5e9e45a75521

### この記事で行うこと
- React（フロント） + CodeIgniter4(バックエンド）を利用
- CodeIgniter4のインストール・設定から、Reactのインストール・設定、最終的にフロント側からバックエンド側へデータの送受信ができている状態までの環境を構築する
### その他の環境
- macOS Monterey(macbook air 2020 ,M1チップ)
- VisualStudio Code

### 参考にしたサイト記事
英語の記事ですが書いてくださった方に感謝

https://mfikri.com/en/blog/react-crud-codeigniter

https://medium.com/@choirulihwan/how-to-create-crud-operation-with-codeigniter-4-and-react-js-fb54d28c923c

## 構築スタート

#### フロントエンド（React）

##### Reactプロジェクト作成

必要ですので、インストールの有無を確認してください。

```bash
node -v
npm -v
```

確認ができたら、 __myProject__ ディレクトリに移動します。
その後下記コマンドを実行。

```bash
npx create-react-app frontend
```

__frontend__ フォルダが作成され、合わせてアプリケーションが内包されます。
続いて、

```bash
npm install react-router-dom axios bulma
```

インストールが完了した後、

```bash
npm start
```
問題なければ、http://localhost:3000 にて画面の表示がされます。

##### コンポーネントを作成する

frontend/srcフォルダ内に、componentsフォルダを作成し、ProductList.js、AddProduct.js、EditProduct.js、のファイルを作成します。
![スクリーンショット 2022-03-09 18.41.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539853/b49c3956-62be-51bb-7241-3632eff45ea7.jpeg)

##### ProductList.js

下記の通りに記載します。

```php
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import { Link } from 'react-router-dom'

const ProductList = () => {
    const [products, setProducts] = useState([]);
 
    useEffect(() => {
        getProducts();
    },[]);
 
    const getProducts = async () => {
        const products = await axios.get('http://localhost:8080/products');
        setProducts(products.data);
    }
 
    const deleteProduct = async (id) =>{
        await axios.delete(`http://localhost:8080/products/${id}`);
        getProducts();
    }
 
    return (
        <div>
            <Link to="/add" className="button is-primary mt-5">Add New</Link>
            <table className="table is-striped is-fullwidth">
                <thead>
                    <tr>
                        <th>No</th>
                        <th>Title</th>
                        <th>Price</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    { products.map((product, index) => (
                        <tr key={product.id}>
                            <td>{index + 1}</td>
                            <td>{product.title}</td>
                            <td>{product.price}</td>
                            <td>
                                <Link to={`/edit/${product.id}`} className="button is-small is-info">Edit</Link>
                                <button onClick={() => deleteProduct(product.id)} className="button is-small is-danger">Delete</button>
                            </td>
                        </tr>
                    )) }
                     
                </tbody>
            </table>
        </div>
    )
}
 
export default ProductList
```

##### AddProduct.js

下記の通りにします。

```php
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import axios from 'axios'
const AddProduct = () => {
    const [title, setTitle] = useState('')
    const [price, setPrice] = useState(0)
    const navigate = useNavigate()
    const saveProduct = async (e) => {
        e.preventDefault();
        await axios.post('http://localhost:8080/products', {
            title: title,
            price: price
        })
        navigate("/")
    }
    return (
        <div>
            <form onSubmit={ saveProduct }>
                <div className="field">
                    <label className="label">Name</label>
                    <input type="text" className="input" value={ title } onChange={ (e) => setTitle(e.target.value) } placeholder="nama" />
                </div>
                <div className="field">
                    <label className="label">Price</label>
                    <input type="text" className="input" value={ price } onChange={ (e) => setPrice(e.target.value) } placeholder="harga" />
                </div>
                <div className="field">
                    <button className="button is-primary">Save</button>&nbsp;
                    <button className="button is-warning" onClick={() => navigate("/")}>Cancel</button>
                </div>
            </form>
        </div>
    )
};
export default AddProduct;
```

##### EditProduct.js

下記の通りにします。

```php
import React, { useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import axios from 'axios'
const EditProduct = () => {
    const [title, setTitle] = useState('')
    const [price, setPrice] = useState(0)
    const navigate = useNavigate()
    const { id } = useParams()
    const updateProduct = async (e) => {
        e.preventDefault();
        await axios.post(`http://localhost:8080/products/update/${id}`, {
            title: title,
            price: price
        })
        navigate("/")
    }
    useEffect(() => {
        getProductById()
    }, [])
    const getProductById = async () => {
        const response = await axios.get(`http://localhost:8080/products/${id}`);
        setTitle(response.data.title)
        setPrice(response.data.price)
    }
    return (
        <div>
            <form onSubmit={ updateProduct }>
                <div className="field">
                    <label className="label">Nama Barang</label>
                    <input type="text" className="input" value={ title } onChange={ (e) => setTitle(e.target.value) } placeholder="nama" />
                </div>
                <div className="field">
                    <label className="label">Harga</label>
                    <input type="text" className="input" value={ price } onChange={ (e) => setPrice(e.target.value) } placeholder="harga" />
                </div>
                <div className="field">
                    <button className="button is-primary">Update</button>&nbsp;
                    <button className="button is-warning" onClick={() => navigate("/")}>Cancel</button>
                </div>
            </form>
        </div>
    )
};
export default EditProduct;
```

##### App.jsを変更する

frontend/srcフォルダ内の, __App.js__ を開きます。
下記の通り変更します。

```php
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import ProductList from './components/ProductList';
import AddProduct from './components/AddProduct';
import EditProduct from './components/EditProduct';
import './App.css';
function App() {
  return (
    <Router>
      <div className="container">
        <Routes>
          <Route exact path="/" element={<ProductList />} />
          <Route path="/add" element={<AddProduct />} />
          <Route path="/edit/:id" element={<EditProduct />} />
        </Routes>
      </div>
    </Router>
  );
}
export default App;
```

##### index.jsを変更する

frontend/srcフォルダ内の, __index.js__ を開きます。
下記の通り変更します。

```php
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bulma/css/bulma.css';
  
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
```

##### 連携ができているか確認する

http://localhost:3000　 へアクセスし、バックエンドとフロントエンドがしっかり連携できているか確認しましょう。

下記のような画面で、操作ができ、テーブルへレコードを追加するなどの動作が確認できれば終了です。![スクリーンショット 2022-03-09 18.56.17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2539853/4b1bbb31-d17b-bd23-31e5-321131e607ac.jpeg)

２記事に渡り、お疲れ様でした。
以上で終了です。