노력이 좋아서
<step72>'react_shoppingmall홈페이지 구현_step6'
zoaseo
2022. 7. 4. 15:28
1)
삭제 하기 구현
product
index.js
import React from 'react';
import "./product.scss";
import axios from 'axios';
import { useParams } from 'react-router-dom';
import useAsync from '../customHook/useAsync';
import { useNavigate } from 'react-router-dom';
async function getProducts(id){
const response = await axios.get(`http://localhost:3000/product/${id}`);
return response.data;
}
const ProductPage = () => {
// product/1
const { id } = useParams();
const [ state ] = useAsync(()=>getProducts(id),[id]);
const { loading, data:product, error } = state;
const navigate = useNavigate();
const productDel = () => {
axios.delete(`http://localhost:3000/product/${id}`)
.then(result=>{
console.log("삭제되었습니다.");
navigate("/"); // 리다이렉션 추가
})
.catch(e=>{
console.log(e);
})
}
if(loading) return <div>로딩중.....</div>
if(error) return <div>에러가 발생했습니다.</div>
if(!product) return <div>로딩중입니다.</div>
return (
<div className='inner'>
<div id="image-box">
<img src={product.imageUrl} alt="" />
</div>
<div id="profile-box">
<ul>
<li>
<div>
<img src="/images/icons/avatar.png" alt="" />
<span>{product.seller}</span>
</div>
</li>
<li>
{product.name}
</li>
<li>
{product.price}원
</li>
<li>등록일 </li>
<li>상세설명 </li>
<li>{product.description}</li>
</ul>
</div>
<div>
<span onClick={productDel}>삭제하기</span>
</div>
</div>
);
};
export default ProductPage;
server.js
const express = require("express");
const cors = require("cors");
const app = express();
const port = 3000;
const models = require('./models');
// 업로드 이미지를 관리하는 스토리지 서버를 연결 -> multer를 사용하겠다.
const multer = require("multer");
// 이미지 파일 요청이 오면 어디에 저장할건지 지정
const upload = multer({
storage: multer.diskStorage({
destination: function(req, file, cb){
// 어디에 저장할거냐? upload/
cb(null, 'upload/')
},
filename: function(req, file, cb){
// 어떤 이름으로 저장할거야?
// file 객체의 오리지널 이름으로 저장하겠다.
cb(null, file.originalname)
}
})
});
// json 형식의 데이터를 처리할 수 있게 설정
app.use(express.json());
// 브라우저 cors이슈를 막기위해 사용(모든 브라우저의 요청을 일정하게 받겠다)
app.use(cors());
// upload폴더에 있는 파일에 접근할 수 있도록 설정
app.use("/upload", express.static("upload"));
// 요청처리
// app.메소드(url, 함수)
// 이미지 파일을 post로 요청이 왔을 때 upload라는 폴더에 이미지를 저장하기
// 이미지가 하나일 때 single('key이름')
app.post('/image', upload.single('image'), (req,res)=>{
const file = req.file;
console.log(file);
res.send({
imageUrl: "http://localhost:3000/"+file.destination+file.filename
})
})
// 요청처리
// app.메소드(url, 함수)
app.get('/products', async(req,res)=>{
// 데이터 베이스 조회하기
models.Product.findAll()
.then(result=>{
console.log("제품전체조회", result);
res.send(result);
})
.catch(e=>{
console.error(e);
res.send("파일 조회에 문제가 있습니다.");
})
});
// method get이고 url은 /product/2로 요청이 온 경우
app.get('/product/:id', async (req,res)=>{
const params = req.params;
// const { id } = params;
// 하나만 조회할 때는 findOne -> select문
models.Product.findOne({
// 조건절
where: {
id: params.id,
}
})
.then(result=>{
res.send(result);
})
.catch(e=>{
console.error(e);
res.send("상품 조회에 문제가 생겼습니다.");
})
});
app.post("/products",(req, res)=>{
// http body에 있는 데이터
const body = req.body;
// body 객체에 있는 값을 각각 변수에 할당
const { name, price, seller, imageUrl, description } = body;
if(!name || !price || !seller) {
res.send("모든 필드를 입력해주세요");
}
else{
// Product테이블에 레코드를 삽입
models.Product.create({
name,
price,
seller,
imageUrl,
description,
}).then(result=>{
console.log("상품 생성 결과 : ", result);
res.send({
result,
})
})
.catch(e=>{
console.error(e);
res.send("상품 업로드에 문제가 생겼습니다.");
})
}
})
// delete 삭제하기
app.delete('/product/:id', async (req,res) => {
const params = req.params;
models.Product.destroy
models.Product.destroy({ where: { id: params.id }})
.then(res.send("상품이 삭제되었습니다."));
})
// 실행
app.listen(port, ()=>{
console.log('쇼핑몰 서버가 동작중입니다.');
// sequelize와 데이터베이스 연결 작업
// 데이터베이스 동기화
models.sequelize
.sync()
.then(()=>{
console.log('DB연결 성공');
})
.catch(()=>{
console.error(e);
console.log('DB연결 에러');
// 서버실행이 안되면 프로세스를 종료
process.exit();
})
});
2)

config
constants.js
export const API_URL = "http://localhost:3000";
import { API_URL } from '../config/constants';
http://localhost:3000 => ${API_URL}
3)
서버에 설치하기
npm install -g nodemon
npx nodemon server.js

4)
배너 슬라이드 달기
참고하기 =>
https://ant.design/components/carousel/
Carousel - Ant Design
Timing of scrolling to the next card/picture.
ant.design
import React from 'react';
import './index.scss';
import axios from 'axios';
import MainProduct from './MainProduct';
import useAsync from '../customHook/useAsync';
import { API_URL } from '../config/constants';
import { Carousel } from 'antd';
async function getProducts(){
const response = await axios.get(`${API_URL}/products`);
return response.data;
}
const contentStyle = {
height: '160px',
color: '#fff',
lineHeight: '160px',
textAlign: 'center',
position: 'absolute',
bottom: '50px',
};
const MainPage = () => {
const onChange = (currentSlide) => {
console.log(currentSlide);
}
const [ state ] = useAsync(getProducts,[])
const { loading, data:product, error } = state;
if(loading) return <div>로딩중.....</div>
if(error) return <div>에러가 발생했습니다.</div>
if(!product) return <div>로딩중입니다.</div>
return (
<div>
<div id="main">
<div id="banner">
<Carousel autoplay afterChange={onChange}>
<div>
<img src="images/banners/banner1.png" alt=""/>
<h3 style={contentStyle}>1</h3>
</div>
<div>
<img src="images/banners/banner1.png" alt=""/>
<h3 style={contentStyle}>2</h3>
</div>
<div>
<img src="images/banners/banner1.png" alt=""/>
<h3 style={contentStyle}>3</h3>
</div>
</Carousel>
</div>
<div id="product-list" className="inner">
<h2>그린조명 최신상품</h2>
<div id="product-items">
{product.map(product=> <MainProduct key={product.id} product={product}/>)}
</div>
</div>
</div>
</div>
);
};
export default MainPage;