기본셋팅
터미널에서 router설치
npm install react-router-dom@6
index.js
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
app.js
import { Routes, Route, Link } from 'react-router-dom'
기본셋팅은 끝.
페이지 주소, 내부 내용 설정
app.js
아래와 같이 <Routes> 로 감싸준 형식 내부에서 <Route>로 지정해줌.
이게 위치한 곳에서 html을 생성하므로, navbar 바로 아래에 작성함.
상세페이지 같은건 map돌려서 생성도 가능함.
<Routes>
// 이걸로 감싸줌
<Route path='/detail0' element={HTML내용} /> //기본형식
<Route path='/detail1' element={<div>상세페이지1</div>} />
<Route path='/detail2' element={<div>상세페이지1</div>} />
//쭉쭉쭉
</Routes>
메인페이지.
<Route path='/' element={ //메인페이지 형식. 내부에서 map 돌릴수 있음.
<div> <Container>
<Row>
{shoes.map((a, i) => {
return (
<Cards shoes={a} i={i}></Cards>
)
})}
</Row>
</Container></div>
} />
이렇게 map으로 돌릴수도 있음.<Detail>컴포넌트는 아래에 작성
(map 말고 되도록 아래 url파라미터 사용법으로 사용할것)
{shoes.map((a, i) => { //라우트 자체를 맵으로 돌려서 만들수도 있음.
return (
<Route path={'/detail' + i} element={<Detail shoes={a} i={i}></Detail>} />
)})}
useParams사용할수 있음 (url파라미터. 매우중요. 반복적인 페이지는 이 방법 사용)
더보기 눌러서 보기.
app.js
<Route path="/detail/:id" element={ <Detail shoes={shoes}/> }/>
detail.js
import { useParams } from 'react-router-dom'
function Detail(props) {
let {id} = useParams();
return (
<>
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes" + ([id] + 1) + ".jpg"} width="100%" />
</div>
<div className="col-md-6">
<h4 className="pt-5">{props.shoes[id].title}</h4>
<p>{props.shoes[id].content}</p>
<p>{props.shoes[id].price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
</>
)
}
export default Detail;
//가능하면 아래쪽 아이디값으로 생성하는 방법을 추천함(페이지 섞이거나, 주소 변경되는것 방지)
이러면 /:url파라미터에 입력한 값을 가져올 수 있음.
파라미터는 여러개 사용해서 여러개의 값을 가져올수도 있음
detail/:입력/:또입력 이렇게
그리고 아이디값으로 주소를 설정하려면 아래와 같이 해줌~~!!
import { useParams } from 'react-router-dom'
function Detail(props) {
let {id} = useParams();
let found = props.shoes.find((e)=>{return e.id == id}); // 타입이 달라서 ===하면 오류남
return (
<>
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes" + (found.id + 1) + ".jpg"} width="100%" />
</div>
<div className="col-md-6">
<h4 className="pt-5">{found.title}</h4>
<p>{found.content}</p>
<p>{found.price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
</>
)
}
export default Detail;
---여기까지가 더보기---
detail.js (함따로 빼봄)
function Detail(props) {
return (
<>
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes" + (props.i + 1) + ".jpg"} width="100%" />
</div>
<div className="col-md-6">
<h4 className="pt-5">{props.shoes.title}</h4>
<p>{props.shoes.content}</p>
<p>{props.shoes.price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
</>
)
}
export default Detail;
app.js 에서 Detail import
import Detail from './Detail'
링크 심어주기
그리고 아까 그 Card컴포넌트의 버튼에 링크를 수정해준다.
<Link to="/detail">링크</Link>형식으로 작성해도 되지만,
아래와 같이 그냥 href 주소에 넣어줘도 작동하지만 더 아래에서 설명할 useNavigate를 사용해도 된다.
function Cards(props) {
return (
<>
<Col lg={3} md={4} className='col'>
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src={"https://codingapple1.github.io/shop/shoes" + (props.i + 1) + ".jpg"} />
<Card.Body>
<Card.Title>{props.shoes.title}</Card.Title>
<Card.Text>
{props.shoes.content}<br />
{props.shoes.price}원
</Card.Text>
<Button on variant="primary" href={'/detail' + props.i}>상세보기</Button>
</Card.Body>
</Card>
</Col>
</>)
}
Navbar의 버튼에 home으로 가는 링크도 심어준다.
<Navbar bg="dark" variant="dark">
<Container>
<Navbar.Brand href="#home">Navbar</Navbar.Brand>
<Nav className="me-auto">
<Nav.Link href="/">Home</Nav.Link>
</Nav>
</Container>
</Navbar>
아래와 같이 잘 작동함.
상세보기 누르면
요렇게 잘 나옴.
홈버튼 누르면 또 잘 돌아감.
useNavigate
app.js 상단에 이렇게 써주고
import { Routes, Route, useNavigate } from 'react-router-dom'
아래와 같이 onclick에 넣어주면 또 잘 작동함.
function App() {
let navigate = useNavigate();
....
return(
<Navbar bg="dark" variant="dark">
<Container>
<Navbar.Brand href="#home">Navbar</Navbar.Brand>
<Nav className="me-auto">
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link onClick={() => { navigate('/detail1') }}>detail1</Nav.Link>
<Nav.Link onClick={() => { navigate(-1) }}>뒤로가기</Nav.Link>
</Nav>
</Container>
</Navbar>
)
}
참고로 navigate(-1)이렇게 하면 뒤로가기 버튼이 됨!
404페이지 만들기
path에 *을 넣고 내용을 작성하면 여기서 설정한 페이지 외 모든 페이지를 지칭함.
<Routes>
{shoes.map((a, i) => {
return (
<Route path={'/detail' + i} element={<Detail shoes={a} i={i}></Detail>} />
)
})}
<Route path='/detail' element={<div>상세페이지</div>} />
<Route path='/about' element={<div>어바웃페이지</div>} />
<Route path="*" element={<div>없는 상품입니다.</div>}/>
</Routes>
nested routes
장점 : 뒤로가기 버튼, 페이지간 이동이 편리함. (모달창도 라우트로 구현 가능)
아래와 같은 route를
이렇게 nested해서 사용할 수도 있음.!!
또한, nested route 사용시 /about/member접속시
about의 element + member의 element 2개 모두 다 보여줌!
이걸 보여주는 장소를 아래처럼 outlet으로 설정해줘야 함.
이렇게!!
function App() {
//중략
return (
//중략
<Routes>
<Route path="*" element={<div>없는 상품입니다.</div>} />
<Route path="/event" element={<Event></Event>}>
<Route path="one" element={<h2>첫 주문시 양배추즙 서비스</h2>}></Route>
<Route path="two" element={<h2>생일 쿠폰 받기</h2>}></Route>
</Route>
</Routes>
</div>
);
}
function Event() {
return (
<>
<h1>오늘의 이벤트</h1>
<Outlet></Outlet>
</>
)
}