Router 페이지 분할하기
Router 시작하기
1.router-dom 설치
방법1. yarn add react-router-dom@5
방법2. npm install react-router-dom@5
2.router-dom 초기 설정
index.js 파일에서 router-dom 초기 설정이 필요하다.
방법1. BrowserRouter
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
방법2. HashRouter
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { HashRouter } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
< HashRouter>
<App />
</HashRouter>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
BrowserRouter와 HashRouter의 비교
HashRouter 방식은 라우팅을 할 때 잘못해서 서버 쪽으로 요청이 가지 않도록 한다. 주소에 #을 붙여 # 뒤에 오는 요청은 서버에 전달되지 않도록 해준다.
다음과 같은 오류 발생시 에디터 재실행
ERROR in ./node_modules/prop-types/node_modules/react-is/index.js
Router 사용법
Router를 import
import {Route} from 'react-router-dom';
<Router> 페이지 분할
<Route path=””>로 페이지를 분할할 수 있다.
<Route path="/">
// 해당 페이지의 html
</Route>
<Route path="/page">
// 해당 페이지의 html
</Route>
exact 속성 사용하여 주소 매칭할 수 있다.
import {Switch} from 'react-router-dom';
<Switch>
<Route exact path="/">
// 해당 페이지의 html
</Route>
<Route path="/page">
// 해당 페이지의 html
</Route>
</Switch>
라우팅을 하게 되면 매칭되는 모든 경로의 html을 불러오게 된다. exact 속성 혹은 <Switch> 사용하면 완전히 매칭되는 페이지만 불러오게 할 수 있다.
컴포넌트를 담아서 사용할 수도 있다.
<Route path="/경로" component={컴포넌트명}></Route>
쇼핑몰 프로젝트 Router 적용하기
페이지 분할
쇼핑몰의 메인페이지와 상품상세페이지 생성
<Route exact path="/">
// 메인페이지 html
</Route>
<Route path="/detail">
// 상품상세페이지 html
</Route>
메인페이지에 html 넣기
<Route exact path="/">
<Alert variant="success" className="background">
<Alert.Heading>20% Season off</Alert.Heading>
<p>
Aww yeah, you successfully read this important alert message. This example
text is going to run a bit longer so that you can see how spacing within an
alert works with this kind of content.
</p>
<hr />
<p className="mb-0">
Whenever you need to, be sure to use margin utilities to keep things nice
and tidy.
</p>
</Alert>
<div className="container">
<div className="row">
{
shoes.map((a,i)=>{ // a : shoes 배열 안의 각각의 데이터
return <Card shoes={shoes[i]} i={i} key={i} /> // shoes와 i를 props로 전송
})
}
</div>
</div>
</Route>
상세페이지 html을 컴포넌트화해서 넣기
App.js
import Detail from './Detail';
<Route path="/detail">
<Detail/>
</Route>
Detail.js
import React from "react";
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%" alt="이미지"/>
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">상품명</h4>
<p>상품설명</p>
<p>120000원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
)
}
export default Detail;
페이지 연결
네브바 메뉴 페이지 이동
Link 컴포넌트 import
import { Link, Route } from 'react-router-dom';
네브바 <Link> 적용
<Link to="/">Home</Link>
<Link to="/detail">Detail</Link>
<Nav.Link as={Link} to="/">Home</Nav.Link>
<Nav.Link as={Link} to="/detail">Detail</Nav.Link>
상세페이지 페이지 뒤로가기
상세페이지 뒤로가기 버튼 생성
<button className="btn btn-primary">뒤로가기</button>
상세페이지 컴포넌트에서 클릭이벤트 적용
import React from "react";
// 1. useHistroy Hook을 import
import { useHistory } from 'react-router-dom';
function Detail(){
// 2. useHistory 변수 생성
let history = useHistory();
return(
<div className="container">
<div className="row">
<div className="col-md-6">
<img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" alt="이미지"/>
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">상품명</h4>
<p>상품설명</p>
<p>120000원</p>
<button className="btn btn-danger">주문하기</button>
<button className="btn btn-primary"
// 3. 클릭 이벤트에 useHistory Hook의 goBack() 함수 적용
onClick={()=>{history.goBack();}}>뒤로가기</button>
</div>
</div>
</div>
)
}
export default Detail;
history.push("/")
: 해당 페이지로 이동할 수 있다.
모든 페이지 html
<Switch>
<Route exact path="/">
// 메인페이지 html
</Route>
<Route path="/detail">
<Detail/>
</Route>
<Route path="/:id">
<div>모든 주소 요청에 이거 보여주셈</div>
</Route>
</Switch>
<Router>의 path=”/:id”는 모든 페이지 주소 요청을 의미한다. 모든 페이지에서 반드시 보여주는 UI를 넣을 때 사용할 수 있다. 여기서 <Switch>를 사용하면 위에서 설명한 exact와 마찬가지로 주소 매칭이 완벽하게 일치하는 UI만 보여준다. 즉, 경로 설정이 이미 완료된 메인페이지와 상세페이지에서는 해당 html을 보여주고 나머지 주소 요청에서 똑같은 html을 보여줄 수 있다.
상세페이지 데이터 바인딩
상품 데이터 전송
state에 저장된 shoes 데이터를 props로 전송
<Route path="/detail">
<Detail shoes={shoes}/>
</Route>
props 전송은 상위 컴포넌트에서 하위 컴포넌트로 전송하는 것이 좋다.
Detail.js
import React from "react";
import { useHistory } from 'react-router-dom';
function Detail(props){
let history = useHistory();
return(
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes"+(props.shoes[0].id+1)+".jpg"} width="100%" alt="이미지"/>
</div>
<div className="col-md-6 mt-4">
<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>
<button className="btn btn-primary" onClick={()=>{history.goBack();}}>뒤로가기</button>
</div>
</div>
</div>
)
}
export default Detail;
상세페이지 파라미터 사용하기
useParams
상품상세페이지에 파라미터를 추가한다.
<!-- App.js -->
<Route path="/detail/:id">
<Detail shoes={shoes}/>
</Route>
useParams Hook을 import한다.
// Detial.js
import { useHistory, useParams } from 'react-router-dom';
useParams를 변수에 담아준다.
let { id } = useParams();
받아온 파라미터 데이터 바인딩한다.
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes"+(props.shoes[id].id+1)+".jpg"} width="100%" alt="이미지"/>
</div>
<div className="col-md-6 mt-4">
<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>
<button className="btn btn-primary" onClick={()=>{history.goBack();}}>뒤로가기</button>
</div>
</div>
</div>
메인페이지 상품 컨테이너 연결하기
메인페이지에서 사용한 Card 컴포넌트에 클릭하면 상세페이지로 이동하게 만들어 준다.
function Card(props){
return(
<div className="col-md-4" onClick={()=>{history.push('/detail/'+props.shoes.id)}}>
<img src={"https://codingapple1.github.io/shop/shoes"+(props.shoes.id+1)+".jpg"} width="100%" alt="이미지"/>
<h4>{props.shoes.title}</h4>
<p>{props.shoes.content}</p>
<p>{props.shoes.price}</p>
</div>
)
}