๐ŸผExpress๋ฅผ ์ด์šฉํ•ด CRUD ํ•˜๊ธฐ(Read & UpdateํŽธ)

alert("april");ยท2023๋…„ 9์›” 21์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
10/17
post-custom-banner


์ถœ์ฒ˜ https://morioh.com/a/4a5e054d3143/crud-operations-with-react-node-express-and-mongodb-a-complete-guide

mysqlํ”„๋กœ๊ทธ๋žจ์€ ์ปดํ“จํ„ฐ๋ฅผ ํ‚ค๋ฉด ๋ฐ”๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ์Œ(3306๋ฒˆ port)

express 3002๋ฒˆ port
react 3001๋ฒˆ port

express์™€ react๋ฅผ ๋™์‹œ์— ์‹คํ–‰?

    concurrently ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ํ•˜์—ฌ
    package.json์— start ๋ช…๋ น์–ด๋ฅผ ๋‘˜ ๋‹ค ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•˜์—ฌ
    npm start๋ฅผ ํ•˜๋ฉด ๋™์‹œ์— ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ผœ์ง€๊ฒŒ ์„ค์ •

	๊ฐ™์€ ์ปดํ“จํ„ฐ ์•ˆ์—์„œ ์„œ๋กœ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์ด
	๋‹ค๋ฅธ ํฌํŠธ์—์„œ ๋™์ž‘ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์— ์ ‘๊ทผ์„ ํ•˜๋ ค๋ฉด
	CORS ์ •์ฑ…์„ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

A. ํด๋ผ์ด์–ธํŠธ์ชฝ์—์„œ ์„ค์ •

    http-proxy-middleware
    ๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜

    setupProxy.js ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ ,
    ์ฃผ์†Œ ๋์— '/api' ๋กœ ๋๋‚˜๋ฉด
    ์„œ๋ฒ„ ํฌํŠธ์ชฝ์œผ๋กœ ๋ณด๋‚ด๊ฒŒ ์„ค์ •์„ ๋งŒ๋“ค์–ด์ค€๋‹ค
    localhost:3001/api ๋กœ get
    ์‹ค์งˆ์ ์œผ๋กœ๋Š”
    localhost:3002/api ๋กœ get ์š”์ฒญ์ด ๊ฐ€๋ฒ„๋ฆฐ๋‹ค
    --> react์—์„œ๋Š” ์ฃผ์†Œ ๋์„ api๋กœ ๋๋‚˜๋Š” ์ฃผ์†Œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค

์ €๋Š” A ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

setupProxy.js

const {createProxyMiddleware} = require('http-proxy-middleware');


module.exports = function(app){
    app.use(
        createProxyMiddleware('/api', {
            target: 'http://localhost:3002',
            changeOrigin:true
        })
    )
}

B. ์„œ๋ฒ„์ชฝ์—์„œ ์„ค์ •(express ํŒŒ์ผ์—์„œ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•)

    cors ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•œ๋‹ค
    npm install cors

    app.use(cors({origin: 'http://localhost:3001'}));

    ํ•ด๋‹น ์ฝ”๋“œ ํ•œ์ค„ ์ถ”๊ฐ€
    (3001๋ฒˆํฌํŠธ ํ—ˆ์šฉํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ)

    ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์š”์ฒญํ•  ๋•Œ
    localhost:3002 get์š”์ฒญ ์ง์ ‘์ ์œผ๋กœ ํ•ด๋„ ์ƒ๊ด€์—†์Œ

    express                    react axios
    res.json('๋ฐฐ์ƒ์—ฝ')  	-->    res.data์— '๋ฐฐ์ƒ์—ฝ'์ด ๋“ค์–ด์žˆ์Œ
    res.json(10)        -->    res.data์— 10์ด ๋“ค์–ด์žˆ์Œ
    res.json([1,2,3])   -->    res.data์— [1,2,3]์ด ๋“ค์–ด์žˆ์Œ

1. ํ•„์š”ํ•œ library๋“ค ์„ค์น˜ ํ›„ package.json์—์„œ "dependencies" ํ™•์ธํ•˜๊ธฐ

npm install concurrently --save

concurrently๋Š” JavaScript ํ”„๋กœ์ ํŠธ์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ช…๋ น์–ด๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋„๋ก ๋„์™€์ฃผ๋Š” ํŒจํ‚ค์ง€์ž…๋‹ˆ๋‹ค. (ChatGPT)

npm install http-proxy-middleware --save

์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ํ•ด๋‹น ํŒจํ‚ค์ง€๋ฅผ require ๋˜๋Š” import ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ JavaScript ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์›น ์„œ๋ฒ„์—์„œ HTTP ํ”„๋ก์‹œ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋ฉฐ, ๋‹ค๋ฅธ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ๊ฒฝ๋กœ๋ฅผ ๋ฆฌ๋ผ์šฐํŒ…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (ChatGPT)

npm install mysql2 --save

2. "scripts" ์— ๋ช…๋ น์–ด ์žฌ์ •์˜ํ•ด์„œ ํฌํŠธ ๋‘๊ฐœ ์—ด๊ธฐ

 "scripts": {
    "client": "set PORT=3001 && react-scripts start",
    "server": "cd server && nodemon app",
    "start": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

package.json

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@emotion/react": "^11.11.1",
    "@emotion/styled": "^11.11.0",
    "@mui/icons-material": "^5.14.3",
    "@mui/material": "^5.14.5",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.5.0",
    "concurrently": "^8.2.1",
    "express": "^4.18.2",
    "http-proxy-middleware": "^2.0.6",
    "mysql2": "^3.6.1",
    "nodemon": "^3.0.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.15.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "client": "set PORT=3001 && react-scripts start",
    "server": "cd server && nodemon app",
    "start": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

app.js

const express = require('express');
// import express from "express"; ์š”์ฆ˜ ๋ฌธ๋ฒ•๊ณผ ๋™์ผํ•œ๋ฐ ๋”ฐ๋กœ ๋ญ˜ ๊น”์•„์ค˜์•ผ ์ด๊ฑธ ์“ธ ์ˆ˜ ์žˆ์Œ
const mysql = require('mysql2');
// const cors = require('cors');

// mysql ์„ค์ •
const pool = mysql.createPool({
    host:'localhost',
    user:'user',
    database:'board',
    password:'1111',
    port:'3306'
});



const app = express();
const port = 3002;

// app.use(cors({origin: 'http://localhost:3001'}));

app.get('/api', (req, res)=>{
    res.send('์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค!');
})

// ๋ชจ๋“  ์‚ฌ์› ์กฐํšŒ
app.get('/api/employees', (req, res)=>{
    
    // mysql์—์„œ employees ํ…Œ์ด๋ธ” ๋ชจ๋“  ํ–‰, ์ปฌ๋Ÿผ ์กฐํšŒ
    pool.query('select * from employees', (err, rows, fields)=>{
        console.log(rows);
        // console.log(fields); ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ ์ •๋ณด๋ผ ์‹ค์งˆ์ ์œผ๋กœ ์ž˜ ์“ฐ์ง€ ์•Š๋Š”๋‹ค
        res.json(rows);
    });

    // res.json();
});

// ์‚ฌ์› ํ•œ๋ช… ์ถ”๊ฐ€
app.post('/api/employees', ()=>{});

app.listen(port, () =>{console.log(`express ์„œ๋ฒ„ ์‹คํ–‰๋จ! ํฌํŠธ:${port}`)});

expressTest.js

import axios from "axios";
import { useRef, useState } from "react";

const ExpressTestPage = ()=>{

    const [employees, setEmployees] = useState([]);

    const onExpressClick = ()=>{
        axios.get('/api')
        .then((res)=>{
            console.log('.์‘๋‹ต ๋ฐ›์•„์˜ด!!', res);
        }).catch((err)=>{ console.log('์‹คํŒจ!!', err)});
    }

    const getEmployees = ()=>{
        axios.get('/api/employees').then((res)=>{
            console.log(res.data);
            setEmployees(res.data);
        }).catch((err)=>{console.log(err)});
    }

    const fetchEmployees =()=>{
        fetch('/api/employees')
            .then((res)=>{return res.json})
            .then((data)=>{console.log(data)})
            .catch((err)=>{console.log(err)});
    }

    const empNameRef = useRef(null); // ์ดˆ๊ธฐ๊ฐ’์„ ๋„ฃ์–ด๋‘”๋‹ค

    const addEmp= ()=>{
        // document.querySelector('#emp_name')
        // document.querySelector๋ฅผ ํ†ตํ•ด ํƒœ๊ทธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹Œ
        // Ref ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํƒœ๊ทธ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค
        console.log(empNameRef.current.value);
    }

    return(
        <>
            <h1>์ž…๋ ฅ</h1>
            <label>
                ์‚ฌ์›์ด๋ฆ„
                <input ref={empNameRef} id="emp_name"/>
            </label>
            <label>
                ์‚ฌ์› ๋ด‰๊ธ‰
                <input id="salary"/>
            </label>
            <button onClick={addEmp}>์ถ”๊ฐ€ ํ•˜๊ธฐ</button>
            
            <h1>์‚ฌ์›๋ชฉ๋ก</h1>
            {employees.map((e)=><div key={e.id}>์‚ฌ์›์ด๋ฆ„ : {e.emp_name}, ์‚ฌ์›๋ฒˆํ˜ธ : {e.id}, ๋ด‰๊ธ‰ : {e.salary}</div>)}
            {/* <div>์‚ฌ์›์ด๋ฆ„: ํ™๊ธธ๋™, ์‚ฌ์›๋ฒˆํ˜ธ: 1, ๋ด‰๊ธ‰: 1000</div>
            <div>์‚ฌ์›์ด๋ฆ„: ํ™๊ธธ๋™, ์‚ฌ์›๋ฒˆํ˜ธ: 1, ๋ด‰๊ธ‰: 1000</div>
            <div>์‚ฌ์›์ด๋ฆ„: ํ™๊ธธ๋™, ์‚ฌ์›๋ฒˆํ˜ธ: 1, ๋ด‰๊ธ‰: 1000</div>
            <div>์‚ฌ์›์ด๋ฆ„: ํ™๊ธธ๋™, ์‚ฌ์›๋ฒˆํ˜ธ: 1, ๋ด‰๊ธ‰: 1000</div>
            <div>์‚ฌ์›์ด๋ฆ„: ํ™๊ธธ๋™, ์‚ฌ์›๋ฒˆํ˜ธ: 1, ๋ด‰๊ธ‰: 1000</div> */}
            <h1>์ต์Šคํ”„๋ ˆ์Šค ํ†ต์‹  ํ…Œ์ŠคํŠธ ํŽ˜์ด์ง€ ์ž…๋‹ˆ๋‹ค!</h1>
            <button onClick={onExpressClick}>๋ฒ„ํŠผ์ž…๋‹ˆ๋‹ค!</button>
            <button onClick={getEmployees}>mysql์—์„œ ๊ฐ€์ ธ์™€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค</button>
            <button onClick={fetchEmployees}>fetch๋กœ ๋ชจ๋“  ์ง์› ์ •๋ณด๋ณด๊ธฐ</button>
        </>
    );
}

export default ExpressTestPage;


๋‚˜์˜ ํฌ๋ง ๋ด‰๊ธ‰์ด๋‹ค...ใ…‹ใ…‹ใ…‹

์‘๋‹ต์„ ์ž˜ ๋ฐ›์•„์˜ค๋Š”๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

IntelliJ ์™€ Oracle์„ ์ด์šฉํ•ด์„œ CRUD๋ฅผ ํ•ด๋ดค์—ˆ๋Š”๋ฐ(๋ฐฑ์—”๋“œ)...
ํ”„๋ก ํŠธ์—”๋“œ ๋งŒ์œผ๋กœ๋„ ์ด๊ฒŒ ๊ฐ€๋Šฅํ•ด์ง€๋‹ค๋‹ˆ ๋„ˆ๋ฌด ์‹ ๊ธฐํ•˜๊ณ  ๋” ๊ฐ„ํŽธํ•œ๊ฒƒ ๊ฐ™๋‹ค๐Ÿฅฐ๐Ÿฅฐ๐Ÿฅฐ

profile
Slowly but surely
post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€