오늘은 React로 쇼핑몰 사이트인 H&M 사이트를 약간 간단한 버젼으로 만들어 볼 것이다.
우선 개발 순서는 아래와 같다.
1. 페이지는 총 전체 상품 페이지, 로그인 페이지, 상품상세 페이지 3개가 있다.
2. 전체 상품페이지에서 전체 상품을 볼 수 있다.
3. 로그인 버튼을 누르면 로그인 페이지가 나온다.
4. 상품 디테일을 눌렀으나. 로그인이 되어있지 않은 경우 로그인 페이지가 먼저 나온다.
5. 로그인이 되어있을 경우에는 상품 디테일 페이지를 볼 수 있다.
6. 로그아웃 버튼을 클릭하면 로그아웃이 된다.
7. 로그아웃이 되면 상품 디테일페이지를 볼 수 없으며 다시 로그인 페이지가 보인다.
8. 로그인을 하면 로그아웃 버튼이 보이고 로그아웃을 하면 로그인 버튼이 보인다.
9. 검색창을 통해 상품을 검색할 수 있다.
1.1 페이지 3개로 나누기 (전체 상품 페이지, 로그인 페이지, 상품 상세 페이지)
우선, 페이지를 여러개로 나누기 위해서 리액트 라우터를 설치하자.
npm install react-router-dom@6
그 후에 index.js에 와서 <React.StrictMode> 태그를 <BrowserRouter>로 바꾸어 <App />을 감싸주자.
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
그런 다음 페이지 3개를 아주아주 간단한게 만들어 보자.
전체 상품 페이지: ProductAll.js
로그인 페이지: Login.js
상품 상세 페이지: ProductDetail.js
ProductAll.js
import React from 'react'
const ProductAll = () => {
return (
<div>
전체 상품 페이지
</div>
)
}
export default ProductAll
Login.js
import React from 'react'
const Login = () => {
return (
<div>
로그인 페이지
</div>
)
}
export default Login
ProductDetail.js
import React from 'react'
const ProductDetail = () => {
return (
<div>
상품 디테일 페이지
</div>
)
}
export default ProductDetail
그 다음 App.js에 와서 Route, Routes를 이용해 페이지를 바꿔줄 수 있는 기능을 추가하자.
App.js
import { Route, Routes } from 'react-router-dom';
import './App.css';
import Login from './page/Login';
import ProductAll from './page/ProductAll';
import ProductDetail from './page/ProductDetail';
function App() {
return (
<div>
<Routes>
<Route path="/" element={<ProductAll/>}/>
<Route path="/login" element={<Login/>}/>
<Route path="/product/:id" element={<ProductDetail/>}/>
</Routes>
</div>
);
}
export default App;
여기까지 하고 페이지가 잘 바뀌는지 테스트를 해보자.
1.2 네비게이션 바 만들기
3개의 페이지가 계속 바뀌어도 네비게이션바는 항상 나오도록 만들어 줄 예정이다.
그렇기 때문에 <Routes> 태그 밖에 <Navbar />라는 컴포넌트를 만들어 준다.
App.js
function App() {
return (
<div>
<Navbar/>
<Routes>
<Route path="/" element={<ProductAll/>}/>
<Route path="/login" element={<Login/>}/>
<Route path="/product/:id" element={<ProductDetail/>}/>
</Routes>
</div>
);
}
Navbar.js
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUser } from '@fortawesome/free-regular-svg-icons'
import { faSearch } from '@fortawesome/free-solid-svg-icons'
const Navbar = () => {
const menuList = ['여성','Divided','남성','신생아/유아', '아동','H&M HOME', '스포츠','Sale', '지속가능성']
return (
<div>
<div>
<div className='login-btn'>
<FontAwesomeIcon icon={faUser} />
<div className='login'>로그인</div>
</div>
</div>
<div className='nav-logo'>
<img width={150} src='https://i.pinimg.com/originals/31/5c/e5/315ce56cdff7fd54307760470bd9f2cf.png'/>
</div>
<div className='search'>
<div className='search-bar'>
<FontAwesomeIcon icon={faSearch}/>
<input type="text" placeholder='검색할 상품을 입력하세요.'/>
</div>
</div>
<div className='menu-area'>
<ul className='menu-list'>
{menuList.map((menu)=>(<li>{menu}</li>))}
</ul>
</div>
</div>
)
}
export default Navbar
App.css
.login-btn{
display: flex;
justify-content: end;
align-items: center;
margin: 30px 30px 0 ;
}
.login{
margin-left: 3px;
cursor: pointer;
}
.nav-logo{
display: flex;
justify-content: center;
align-items: center;
}
.menu-area{
display: flex;
justify-content: center;
align-items: center;
}
.menu-list{
display: flex;
list-style: none;
padding:0;
}
.menu-list li{
padding:10px;
cursor: pointer;
}
.search{
display: flex;
justify-content: end;
align-items: center;
}
.search input{
border: none;
margin-left: 3px;
}
.search-bar{
border-bottom: 2px solid black;
margin-right: 30px;
padding: 5px;
}
2. 전체 상품페이지에서 전체 상품 보여주기
(전체 상품 목록을 보여주려면 백엔드가 필요하다. 하지만 프론트를 공부하고 있으니 백엔드 없이 하는 방법으로 해보자.)
우선 json.server를 다운받자.
https://www.npmjs.com/package/json-server
npm install -g json-server
그 후에 db.json 파일을 만들어 그 안에 데이터를 넣어준다.
아래는 db.json 안에 들어갈 데이터의 내용이다.
{
"products": [
{
"id": 0,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/ec/ef/ecef9d77c56c519e24a76b83331ae2c18f73f50d.jpg],origin[dam],category[],type[LOOKBOOK],res[y],hmver[1]&call=url[file:/product/main]",
"title": "벨티드 트윌 코트",
"price": 99900,
"choice": true,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 1,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/af/50/af50afa939c28ba24fd263fb573b4ad5f0858b14.jpg],origin[dam],category[],type[DESCRIPTIVESTILLLIFE],res[y],hmver[2]&call=url[file:/product/main]",
"title": "슬림핏 맘 하이웨이스트 앵클 진",
"price": 29900,
"choice": true,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 2,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/7a/49/7a4980a16ce6888b33481763ea1f0a05807f50d1.jpg],origin[dam],category[],type[LOOKBOOK],res[y],hmver[1]&call=url[file:/product/main]",
"title": "와이드 하이웨이스트 진",
"price": 39900,
"choice": false,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 3,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/10/34/10341727ce95aae07695e7b13392a1d802ffe1f3.jpg],origin[dam],category[],type[LOOKBOOK],res[y],hmver[1]&call=url[file:/product/main]",
"title": "퍼프 슬리브 드레스",
"price": 39900,
"choice": false,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 4,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/0f/46/0f463d61dbddb48bea8e329d9693f17fbff7f925.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "프릴 디테일 블라우스",
"price": 29900,
"choice": true,
"new": false,
"size": ["S", "M", "L"]
},
{
"id": 5,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/95/20/9520af2b69e69ef18fbad1d2673d47b1afe2b107.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "자카드 셔츠 드레스",
"price": 39900,
"choice": false,
"new": false,
"size": ["S", "M", "L"]
},
{
"id": 6,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/66/eb/66ebc8ebbdc939176137327d43db5c22d2d0292f.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "더블 브레스티드 재킷",
"price": 39900,
"choice": true,
"new": false,
"size": ["S", "M", "L"]
},
{
"id": 7,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/be/3c/be3cfb9b7d99937f42b99b859dee546f8a3216b7.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "오버사이즈 집업 후디",
"price": 99900,
"choice": false,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 8,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/ad/e9/ade9a2fa40f186b2db875ceb35ca279ca99b300a.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "프린트 크롭트 탑",
"price": 14900,
"choice": true,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 9,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/44/a9/44a926e37e57244c829c3f7a049fc8aa629d276e.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "프린트 티셔츠",
"price": 19900,
"choice": false,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 10,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/fa/54/fa547c437bf08076aa46dd66f1a2e6a2cf4a4e3e.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "와이드 트윌 팬츠",
"price": 19900,
"choice": true,
"new": false,
"size": ["S", "M", "L"]
},
{
"id": 11,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/d1/aa/d1aa5d5d4a3d0699689e7f6187514ad70dc958d6.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "플레어 로라이즈 진",
"price": 29900,
"choice": true,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 12,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/ec/6c/ec6c0b3d387ce9b51d68ee440b979291e929c773.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "프린트 크롭트 탑",
"price": 14900,
"choice": true,
"new": true,
"size": ["S", "M", "L"]
},
{
"id": 13,
"img": "https://lp2.hm.com/hmgoepprod?set=source[/37/43/37434b12a61d3e75cb8e7fcb2e0b6cd6ca028c5f.jpg],origin[dam],category[],type[LOOKBOOK],res[z],hmver[1]&call=url[file:/product/main]",
"title": "플레어 로라이즈 진",
"price": 29900,
"choice": false,
"new": false,
"size": ["S", "M", "L"]
}
]
}
데이터까지 넣었다면 이제 json server를 실행시켜야 한다.
그렇게 하기 위해서 새로운 터미널에 아래 코드를 작성한다.
npx json-server --watch db.json --port 5000
여기까지 되면 API만 호출해 주면 된다.
다시 ProductAll.js로 와서 아래처럼 작성해주자. (부트스트랩을 사용했다.)
ProductAll.js
import React, { useEffect, useState } from 'react'
import { Container,Row, Col } from 'react-bootstrap';
import ProductCard from '../component/ProductCard';
const ProductAll = () => {
const [productList, setProductList] = useState([]);
const getProducts=async()=>{
let url = `http://localhost:5000/products`
let response = await fetch(url)
let data = await response.json()
setProductList(data)
}
useEffect(()=>{
getProducts()
},[])
return (
<div>
<Container>
<Row>
{productList.map(item=><Col lg={3}><ProductCard item={item} /></Col> )}
</Row>
</Container>
</div>
)
}
export default ProductAll
ProductCard.js
import React from "react";
const ProductCard = ({ item }) => {
return (
<div>
<img width={300} src={item?.img} />
<div>{item?.choice == true ? "Conscious choice" : " "}</div>
<div>{item?.title}</div>
<div>{item?.price}</div>
<div>{item?.new == true ? "신제품" : ""}</div>
</div>
);
};
export default ProductCard;
'React' 카테고리의 다른 글
[React] 리액트로 아주 간단한 todo-list 만들기 (0) | 2023.09.24 |
---|---|
[React] 간단한 코드로 애니메이션 만드는 법(Fade, Zoom, Flip 등) (0) | 2023.07.13 |
[React] API로 날씨 앱 만들기 3(OpenWeather API 사용) (0) | 2023.03.01 |
[React] reactrouter로 여러개의 웹페이지 만들기 (0) | 2023.02.20 |
[React] API로 날씨 앱 만들기 2(OpenWeather API 사용) (0) | 2023.02.15 |