routing : 설치
라우팅 ? 페이지를 여러개 만드는것
라우팅은 react-router-dom 라이브러리 이용해야한다
yarn add react-router-dom@5
npm install react-router-dom@5
@5를 붙여야한다!
index.js 셋팅
이 파일은 App.js에 있는 <App> 컴포넌트를 index.html에 꽂아주세요~ 뭐 이런 작업을 시키는 파일이다.
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();
BrowserRouter vs HashRouter 🤔
HashRouter은 사이트 주소 뒤에 #이 추가된다.
#뒤에 적은 것은 서버로 전달이 되지 않는다.
⇒ 라우팅을 좀 더 안전하게 도와준다.
반면 BrowserRouter 은 #기호가 없이 동작한다.
라우팅을 리액트가 아니라 서버에게 요청할 수 있어서 위험하다.
따라서 서버에 요청하지 않기 위해서 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();
상세페이지와 메인페이지로 나누기
import {Link, Route, Switch} from 'react-router-dom'
1. 일단 import하기
<Route path="/">
<div>메인페이지에요</div>
</Route>
<Route path="/detail">
<div>디테일페이지에요</div>
</Route>
2. <Route path=”/경로”></Route>
3. <Route>안에 HTML 적기
근데 왜 /detail경로로 접속했는데 /경로 내용이 보일까?
리액트는 매칭되는 것을 다 보여줌, 이게 싫다면exact exact 를 추가해준다.
<Route exact path=”/경로”></Route>
Route를 쓰는 다른 방법
<Route path="/any" component={}></Route>
컴포넌트를 보여주고 싶을 때
<Route exact path="/">
<div className="Jumbotron">
<h1>20% Season off Sale</h1>
<p>
Welcome to the sticker shop. There is a season sale, so please check
the notice. thank you.
</p>
</div>
<div className="container">
<div className="row">
{sticker.map((a, i) => {
return <Contents sticker={a} i={i} key={i}></Contents>;
})}
</div>
</div>
</Route>
메인 화면을 보여주는 코드이다.
Jumbotron과 메인 상품을 보여준다.
이것을 다시 컴포넌트로 만들어서 빼도 된다.
<React Router 특징>
페이지마다 다른 HTML 파일이 아닌 하나의 index.html만 있으면 된다.
문제! ✔️
상세페이지를 컴포넌트 화 할것이다. (다른 파일로 빼서)
Detail.js
import React, { useState } from "react";
function Detail() {
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={require(`./Sketch001.jpg`)} width="100%" />
</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;
리액트 컴포넌트를 만들때 리액트에서 제공하는 기본 문법
import React, { useState } from "react";
를 꼭 상단에 써줘야한다.
export default Detail;
로 내보내기!
사용할때는?
import Detail from "./Detail.js";
<Route path="/detail">
<Detail />
</Route>
Link 태그로 페이지 이동버튼 만들기
<Link to="/">Home</Link>
react-router 문법을 이용한 이동하는 버튼 만들기!
<Link to="경로">버튼</Link>
페이지 이동시키는 다른 방법 (뒤로가기)
**import { useHistory } from "react-router-dom";**
let history = useHistory();
<button
className="btn"
onClick={() => {
**history.push("/");
//push로 경로 이동가능**
}}
>
뒤로가기
</button>
history 오브젝트는 이동했던 모든 url 페이지들을 담은 것이다.
history.goBack();
이전 방문했던 사이트로 돌아감
Switch컴포넌트?
내가 컴포넌트들을 보여줄 때, path=”/:id” 일때 (/모든문자 라는 경로를 의미)
<Route path="/:id">
<div>아무거나 보여주기</div>
</Route>
매칭이 되기만 하면 다 보여줌!
만약 매칭이 되었을때 맨 처음것만 보여주고 싶을때 사용하는 것 Switch
“여러개가 맞아도 하나만 보여주세요~”
**<Switch>**
<Route exact path="/">
<div className="Jumbotron">
<h1>20% Season off Sale</h1>
<p>
Welcome to the sticker shop. There is a season sale, so please
check the notice. thank you.
</p>
</div>
<div className="container">
<div className="row">
{sticker.map((a, i) => {
return <Contents sticker={a} i={i} key={i}></Contents>;
})}
</div>
</div>
</Route>
<Route path="/detail">
<Detail />
</Route>
<Route path="/:id">
<div>아무거나 보여주기</div>
</Route>
**</Switch>**
모든 라우터를 Switch로 감싸기
<Detail> 컴포넌트에 데이터바인딩하기
Detail페이지에 첫번째 상세 내용 상품 데이터 바인딩 하기
hint? props문법으로 전송!
<Route path="/detail">
<Detail sticker={sticker} />
</Route>
import React, { useState } 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={require(`./Sketch001.jpg`)} width="100%" />
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{props.sticker[0].title}</h4>
<p>{props.sticker[0].content}</p>
<p>{props.sticker[0].price}</p>
<button className="btn btn-danger">Order</button>
<button
className="btn"
onClick={() => {
history.goBack();
}}
>
Back
</button>
</div>
</div>
</div>
);
}
export default Detail;
데이터를 함수 안에 넣어도 되지만, 이는 옳바른 방법이 아니다.
중요한 데이터는 App 컴포넌트에 보관하자!
데이터는 상위→하위 (props) 를 사용하는 것이 좋다.
URL Parameter, userParams
/detail/0 0번째 상품 보여주기
/detail/1 1번째 상품 보여주기
/detail/2 2번째 상품 보여주기
<Route path="/detail/:id">
<Detail sticker={sticker} />
</Route>
: 기호는 뒤에 아무 문자가 오든지 페이지로 이동시켜주라는 의미
이것이 url parameter 이다.
import { useHistory,useParams } from "react-router-dom";
let { id } = useParams();
//파라미터 값을 저장해서 변수로 사용할 수 있다.
// '/:id' 자리에 사용자가 입력한 값
<img
src={require(`./Sketch00${parseInt(id) + 1}.jpg`)}
width="100%"
/>
<h4 className="pt-5">{props.sticker[id].title}</h4>
<p>{props.sticker[id].content}</p>
<p>{props.sticker[id].price}</p>
이미지는 다음과 같이 처리하였다.
URL Parameter 응용 문제!✔️
만약 데이터의 순서가 바뀐다면 상세페이지도 이상해진다.
예를 들어 가격순으로 정렬 시 , shose라는 state가 변경이 되는데, 이때 detail/0 접속 시 엉뚱한 상품이 뜬다.
이를 해결 하는 방법은?
hint? 상품의 id는 영구적인 번호로 활용하자
<내가 짠 코드>
App.js 정렬함수, 콘텐츠 컴포넌트 이미지 부분 수정
function PriceSorting() {
var newArray = [...sticker];
newArray.sort((a, b) => {
return a.price - b.price;
});
console.log(newArray);
stickerChange(newArray);
}
function Contents(props) {
return (
<div className="col-md-4">
<img
src={require(`./Sketch00${**props.sticker.id + 1**}.jpg`)}
width="100%"
/>
<h4>{props.sticker.title}</h4>
<p>
{props.sticker.content} & {props.sticker.price}
</p>
</div>
);
}
Detail.js
import React, { useState } from "react";
import { useHistory, useParams } from "react-router-dom";
function Detail(props) {
let history = useHistory();
let { id } = useParams();
let realID = props.sticker[id].id;
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img
src={require(`./Sketch00${parseInt(id) + 1}.jpg`)}
width="100%"
/>
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{props.sticker[realID].title}</h4>
<p>{props.sticker[realID].content}</p>
<p>{props.sticker[realID].price}</p>
<p>{props.sticker[id].id}</p>
<button className="btn btn-danger">Order</button>
<button
className="btn"
onClick={() => {
history.goBack();
}}
>
Back
</button>
</div>
</div>
</div>
);
}
export default Detail;
답안지 확인
(Detail.js 파일)
import React from 'react';
import { useHistory, useParams } from 'react-router-dom';
function Detail(props){
let { id } = useParams();
let 찾은상품 = props.shoes.find(function(상품){
return 상품.id == id
});
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 mt-4">
<h4 className="pt-5">{찾은상품.title}</h4>
<p>{찾은상품.content}</p>
<p>{찾은상품.price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
)
};
export default Detail
답안에는 find() 라는 ES6 신문법을 사용하였는데, 이는 Array 안에서 원하는 자료를 찾고싶을 때 사용한다.
- find()는 array 뒤에 붙일 수 있으며, 안에 콜백함수 들어간다.
- 콜백함수 내의 파라미터는 array 안에 있던 하나하나의 데이터를 의미
- return 오른쪽엔 조건식 가능
- 현재 URL의 /:id에 적힌 값과 상품의 영구번호가 같은지 비교
'Front-end > React' 카테고리의 다른 글
[React] 코딩애플 blog-part2-4 (Lifecycle & Hook) (0) | 2021.12.28 |
---|---|
[React] 코딩애플 blog-part2-3 (styled-components & SASS ) (0) | 2021.12.28 |
[React] 코딩애플 blog-part2-1 (import/export/Component화 + 반복문) (0) | 2021.12.26 |
[React] 코딩애플 blog -6 (0) | 2021.12.09 |
[React] 코딩애플 blog -5 (0) | 2021.12.09 |