리액트는
SinglePageApplication 사용한다. 줄여서SPA라고 한다.
SPA란 페이지 전체가 바뀌는 것이 아니라 필요한 부분만 업데이트를 하는 방식으로 페이지 새로고침이 되지 않는다 .
SPA는 빠르게 페이지 전환이 되는 장점이 있지만 단점도 있다.
첫 화면의 로딩시간이 길고, 자바스크립트의 파일이 커진다

npm install react-router-dom@6<App />, <BrowserRouter>로 감싸주기//index.js
import { BrowserRouter } from "react-router-dom";
root.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
);
Routes, Route 상단에 import 해오기import { Routes, Route } from "react-router-dom";
//리액트라우터 작성방법
<Routes>
<Route path="/detail/:id" element={<Detail />} />
</Routes>
Routes 하위에 Route를 넣어야 하고, Route는 페이지를 의미한다. Route가 많아지면 많아질 수록 페이지가 늘어가는 것을 확인 할 수 있다./ 이렇게 적으면 메인페이지를 의미하고, * 이렇게 적으면 해당하는 URL 이 외에 모든 것을 의미하기 때문에 element 안에 <div>없는 페이지 입니다...</div> 이런식으로 해당 URL이 아닐 경우 보여지는 페이지를 따로 만들 수도 있다.Route안에는 path와 element가 있는데 path=" " 안에는 파일 경로를 적어줄 수 있고,element={ } 안에는 페이지에 대한 내용을 html로 적을수도 있고, 컴포넌트화 해서 넣을 수도 있다Link 컴포넌트가 있다 각각 url 경로로 이동하는 링크를 설정해줄 수 있는데 화면에 렌더링 될 때는 기본값이 스타일을 안 준 <a>태그 처럼 표시 되기 때문에 UI가 예쁘지 않다. 보통은 UI를 먼저 만들고 useNavigate를 사용하는데 Link 컴포넌트 사용하는 방법을 먼저 살펴보면 ...import { Routes, Route, Link } from "react-router-dom";
<Link to="/">홈</Link> //메인페이지 이동
<Link to="/detail">상세페이지</Link> //detail 상세페이지 이동
import { Routes, Route, Link, useNavigate } from "react-router-dom";
function App(){
const navigate = useNavigate()
return ( //버튼 클릭 시 detail페이지로 이동하기
<button
onClick={()=>{
navigate('/detail') //detail페이지로 이동
}}
>
detail 이동 버튼
</button>
)
}
//data.jsx
const data = [
{ //검정신발
id: 1,
title: "White and Black",
content: "Born in France",
price: `120,000`,
},
{ // 빨강신발
id: 2,
title: "Red Knit",
content: "Born in Seoul",
price: `110,000`,
},
{ //회색신발
id: 3,
title: "Grey Yordan",
content: "Born in the States",
price: `130,000`,
},
];
export default data;
//App.js
import { Route, Routes, useNavigate } from "react-router-dom";
import { Navbar, Container } from "react-bootstrap";
import "./App.css";
import data from "./data"; //3개의 신발 상품 데이터
import Card from "./components/Card";
import Detail from "./pages/Detail";
function App() {
const navigate = useNavigate(); //페이지 이동을 도와주는 함수
const shoes = data; //객체 data를 변수 shoes에 넣음
return (
<div className="App">
<Navbar bg="light" variant="light">
<Container>
<Navbar.Brand
onClick={() => {
navigate("/");
}}
>
ShoeShop {/** 메인로고버튼*/}
</Navbar.Brand>
</Container>
</Navbar>
<Routes>
<Route // 메인페이지 Card부분
path="/"
element={
<>
<div className="main-bg"></div>
<Container>
<div className="row">
{shoes.map((item, i) => ( // 3개 신발 상품 데이터 반복생성
<Card item={item} i={i} key={i} />
))}
</div>
</Container>
</>
}
/>
<Route path="/detail/:id" element={<Detail shoes={shoes} />} /> // 상세페이지 Detail
</Routes>
</div>
);
}
export default App;
필요한 컴포넌트들을 import 해왔고, 위에서 부터 설명하자면 메인로고 버튼에 useNavigate를 사용해서 메인페이지로 이동할 수 있게 만들었다
Route로 페이지를 만들고, 메인페이지에 map을 사용하여 3개 상품을 반복생성하였다. 3개의 상품은 Card라는 컴포넌트 안에 데이터가 들어가 있다. Card에 item을 넘겨준 이유는 상품명, 상품내용, 상품가격을 다 다르게 보여줘야 하기 때문에 프롭스로 item을 넘겨줬고, i를 넘겨준 이유는 상품 이미지를 다 다르게 보여줘야 하기 때문에 넣었다. 이렇게 반복생성을 할 때에는 key 값을 넣어줘야 오류가 안 난다
Route로 detail 페이지를 만들고, 3개의 상품이 각각 클릭 됐을 때 detail페이지의 경로가 다 다르고 데이터도 달라야 하기 때문에 경로를 /:id로 만들어준 다음에 Detail컴포넌트를 컴포넌트화 해서 내용으로 넣어주었다. 프롭스로 shoes를 넘겨준 이유는 경로 id와 shoes(data)의 영구번호인 id를 비교해서 그에 맞는 내용과 이미지를 보여줘야 하기 때문에 넣었다
//Card.jsx
import { useNavigate } from "react-router-dom";
const Card = ({ item, i }) => {
const navigate = useNavigate();
return (
<div className="col-md-4">
<img
src={"https://codingapple1.github.io/shop/shoes" + (i + 1) + ".jpg"}
width="80%"
alt=""
onClick={() => navigate(`/detail/${item.id}`)} //id는 1, 2, 3
/>
<h4>{item.title}</h4>
<h6>{item.content}</h6>
<p>{item.price}원</p>
</div>
);
};
export default Card;
프롭스로 전달 받은 item은 shoes와 같은 의미이다. 그래서 item.title을 하게되면 상품명이 잘 나타나는 것을 확인 할 수 있다. map에서 두번째 인자 i는 0부터 시작하는 정수이고, 즉 인덱스 번호로 표현할 수 있다.
이미지 src i + 1에 대한 설명을 하자면 이미지는 1, 2, 3인데 i는 0부터 시작하기 때문에 +1을 해준 것이다
onClick으로 navigate를 이용해 URL 경로를 적어주었다. (/detail/${item.id}) 이 경로에서 item.id는 영구번호로 1, 2, 3의 값이 각각 들어있다 이미지 클릭 시 경로가 달라야 하기 때문에 영구번호로 넣어준 것이다 사실상 저 코드의 의미는 shoes.id와도 같은 의미인 걸 확인 할 수 있다 프롭스로 item을 받아왔기 때문에 item을 쓴 것이다
//Detail.jsx
import { Container } from "react-bootstrap";
import { useParams } from "react-router-dom";
const Detail = ({ shoes }) => {
const { id } = useParams();
const products = shoes.find((product) => product.id === Number(id));
return (
<Container>
<div className="d-flex justify-content-center">
<div className="col-md-8">
<img
src={
"https://codingapple1.github.io/shop/shoes" + products.id + ".jpg"
}
width="80%"
alt=""
/>
<h4>{products.title}</h4>
<h6>{products.content}</h6>
<p>{products.price}</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</Container>
);
};
export default Detail;
path="/detail/:id" URL 경로에 id를 useParams로 가져왔다 URL id와 shoes의 영구번호 id를 비교해서 그에 맞는 데이터만 보여지게 하기위해 find 메서드를 사용했다 이때 ==과 ===의 차이점을 정확히 알 수 있게 되었는데 URL id는 문자열이고, shoes의 id는 숫자였다 그렇기 때문에 두개를 비교하면 당연히 오류가 날 수 밖에 없다 그래서 URL id를 Number 또는 parseint를 사용해서 숫자로 바꿔주게 되면 오류가 해결된다