상세페이지가 보여줄 html을 담기 위해 Detail.js 파일을 생성한다.
아래 코드를 넣어준다.
/* eslint-disable */
function Detail() {
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img
src="https://codingapple1.github.io/shop/shoes1.jpg"
width="100%"
/>
</div>
<div className="col-md-6">
<h4 className="pt-5">상품명</h4>
<p>상품설명</p>
<p>120000원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
);
}
export default Detail;
그리고 App.js에서 아래코드로 변경한다.
<Routes>
<Route
path="/"
element={
<>
<div className="main-bg"></div>
<Shoe shoes={shoes}></Shoe>
</>
}
/>
<Route path="/detail" element={<Detail />} />
</Routes>
Detail Component를 적용한 모습이다.
이처럼 path가 "/"인 부분도 깔끔하게 하기 위해 Component를 만들어 정리해주자.
이제 routes 폴더를 따로 만들어 관리해주자.
동시에 component 폴더도 만들고 Shoe.js를 옮긴다.
routes 폴더 안에 Home.js 생성
/* eslint-disable */
import Shoe from "../components/Shoe";
function Home(props) {
return (
<>
<div className="main-bg"></div>
<Shoe shoes={props.shoes} />
</>
);
}
export default Home;
또 routes 폴더 안에 About.js 생성
/* eslint-disable */
import { Outlet } from "react-router-dom";
function About() {
return (
<div>
<h3>About 페이지</h3>
<Outlet></Outlet>
</div>
);
}
export default About;
Shoe.js 수정
/* eslint-disable */
function Shoe(props) {
return (
<div className="container">
<div className="row">
{props.shoes.map((item, index) => {
return (
<div className="col-md-4" key={index}>
<img src={item.src} width="80%" />
<h4>{item.title}</h4>
<p>{item.content}</p>
<p>{item.price}</p>
</div>
);
})}
</div>
</div>
);
}
export default Shoe;
App.js 수정
/* eslint-disable */
import "./App.css";
import { Button, Navbar, Container, Nav } from "react-bootstrap";
import { Routes, Route, Link, useNavigate, Outlet } from "react-router-dom";
import { useState } from "react";
import data from "./shoes";
import Detail from "./routes/Detail";
import Home from "./routes/Home";
import About from "./routes/About";
function App() {
const [shoes, setshoes] = useState(data);
const navigate = useNavigate();
return (
<div className="App">
<Navbar bg="dark" variant="dark">
<Container>
<Navbar.Brand
onClick={() => {
navigate("/");
}}
>
My shop
</Navbar.Brand>
<Nav className="me-auto">
<Nav.Link
onClick={() => {
navigate("/");
}}
>
Home
</Nav.Link>
<Nav.Link
onClick={() => {
navigate("/detail");
}}
>
Detail
</Nav.Link>
</Nav>
</Container>
</Navbar>
<Routes>
<Route path="/" element={<Home shoes={shoes} />} />
<Route path="/detail" element={<Detail shoes={shoes} />} />
<Route path="/about" element={<About />}>
<Route path="member" element={<div>멤버정보</div>} />
<Route path="location" element={<div>위치정보</div>} />
</Route>
<Route path="*" element={<div>없는 페이지입니다.</div>} />
</Routes>
</div>
);
}
export default App;
코드가 훨씬 보기 깔끔해졌다.
Home 과 Detail 페이지에 props 를 이용하여 shoes를 전달해주었다.
Route 안에 Route (nested route)
/about/member, /about/location 으로 접속하면
<About/>페이지와 그 안에 있는<Outlet/>위치에 각 element 요소가 나타난다.
Route path="*"
path에 없는 주소로 이동할때 보여주는 페이지
App.js에서
Link 태그는 안이쁘니 지워버리고 useNavigate()을 이용해 메뉴바에 링크를 간단하게 걸어주었다.
navagate 추가 기능
navigate(1) 👉 앞으로가기
navigate(2) 👉 2번앞으로가기
navigate(-1) 👉 뒤로가기
navigate(-2) 👉 2번뒤로가기
.
.
상세페이지에 데이터 바인딩을 해보자.
/* eslint-disable */
function Detail(props) {
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img
src={props.shoes[0].src}
width="100%"
/>
</div>
<div className="col-md-6">
<h4 className="pt-5">{props.shoes[0].title}</h4>
<p>{props.shoes[0].content}</p>
<p>{props.shoes[0].price}</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
);
}
export default Detail;
App.js 에서 /detail/ 뒤에 어느 글자가 와도 <Detail/> 페이지로 이동할 수 있게 수정해보자.
<Route path="/detail/:id" element={<Detail shoes={shoes} />} />
그리고 Detail.js 를 아래와 같이 수정해준다.
/* eslint-disable */
import { useParams } from "react-router-dom";
import shoes from "../shoes";
function Detail() {
const { id } = useParams();
const shoe = shoes.filter((shoe) => shoe.id === Number(id));
if (shoe.length === 0) {
return (
<div>
<h3>해당 상품은 존재하지 않습니다.</h3>
</div>
);
} else {
return (
<div className="row">
<div className="col-md-6">
<img src={shoe[0].src} width="100%" />
</div>
<div className="col-md-6">
<h4 className="pt-5">{shoe[0].title}</h4>
<p>{shoe[0].content}</p>
<p>{shoe[0].price}</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
);
}
}
export default Detail;
useParams() 가 :id 부분에 있는 글자를 가져와준다.
그 글자를 id라는 변수에 넣고 이 변수는 String 이기 때문에 Number()로 숫자로 변형해줘야 사용할 수 있다.
그리고 filter() 를 사용하여 속성 id가 해당 숫자와 같은 객체의 배열을 shoe 변수에 담는다.
filter()의 반환 값은 배열인 것을 주의해야한다!
그런데, :id에 물품의 id가 아닌 이상한 글자가 오면?
if (shoe.length === 0) 조건식을 이용하여 해당 상품이 없다고 보여주면 된다.
이제 detail/상품번호 이렇게 하면 id가 상품번호와 같은 상품 상세화면을 보여줄 수 있다.