이번 포스팅에서는 React Router를 사용하여 사용자가 주소창에 /상세주소
를 입력했을 때 해당하는 페이지로 이동할 수 있도록 해 볼 것이다. 현재 진행 중인 쇼핑몰 페이지에 적용해 본다면 /detail
로 접속하면 상품 상세 페이지로, /cart
로 접속하면 장바구니 페이지로 이동할 수 있도록 구현해 보자.
이를 구현하기 위해서는 먼저 리액트 라우터에 대한 이해가 필요하다.
사용자가 입력한 주소를 감지하는 역할을 하며, 여러 환경에서 동작할 수 있도록 여러 종류의 라우터 컴포넌트를 제공한다.
우선 내 프로젝트 터미널에 아래 코드를 작성하여 리액트 라우터 돔 라이브러리를 설치해야 한다. v6 버전으로 설치해 보자!
npm install react-router-dom@6
설치가 완료되었으면 index.js
에 들어가 아래와 같이 코드를 추가해 준다. 기존 App 컴포넌트를 BrowserRouter 컴포넌트로 감싸 줘야 하기 때문이다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom'; // 이 부분이 추가됨!
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter> // 이 부분이 추가됨!
<App />
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
이제 App.js
로 가서 react-router-dom
에서 필요한 몇 가지를 import 해 준다.
...
import { Route, Routes, Link, useNavigate, Outlet } from 'react-router-dom';
function App() {
...
return (
<div className="App">
<Routes>
<Route/>
<Route/>
</Routes>
...
이렇게 하면 기본 세팅은 끝!
위에서 App.js에서 Routes
컴포넌트를 작성해 보았다. Routes 안에는 여러 개의 Route
들이 있는 구조인데, 각 Route 마다 원하는 페이지의 주소와 그 주소로 접속했을 때 보여 주고 싶은 페이지를 작성하면 된다.
주소는 path
속성에, 페이지는 element
속성에 작성한다.
<Routes>
<Route path='/상세주소1' element={<div>보여주고싶은페이지1</div>} />
<Route path='/상세주소2' element={<div>보여주고싶은페이지2</div>} />
</Routes>
Link는 버튼을 만들고, 그 버튼을 클릭했을 때 해당 주소로 이동시켜 주는 기능을 한다.
<Link to='/버튼클릭시이동할주소'>버튼</Link>
navigate() 함수 또한 클릭 시 해당 주소로 이동시켜 주는 기능을 한다. 보통 기존 버튼을 onClick 했을 때 함수가 수행되도록 코드를 작성한다.
navigate('/주소') // 해당 주소로 이동
navigate('1') // 앞으로 이동
navigate('-1') // 뒤로 이동
만약 주소를 /주소1/주소2
식으로 작성해야 한다면 어떻게 할까? 이때는 nested routes를 사용하여 좀 더 간단히 작성해 볼 수 있다.
<Route path='/주소1' element={<About/>}>
<Route path='주소2' element={<div>주소2페이지</div>}></Route>
</Route>
/주소1/주소2
에 접속 시 주소1 페이지와 주소2 페이지 내용이 모두 보여지도록 할 수 있는데, 이때 사용하는 것이 Outlet이다.
...
function About(){
return(
<div>
<h4>페이지1내용</h4>
<Outlet></Outlet>
</div>
)
}
이런 식으로 작성하면
<Route path='주소2' element={<div>주소2페이지</div>}></Route>
위 코드의 <div>주소2페이지</div>
이 부분이 <Outlet></Outlet>
에 들어가게 된다. 따라서 내가 내용을 보여 주고 싶은 부분에 Outlet을 적절히 작성해 주면 여러 형태로 내용을 출력할 수 있다. 😎
useParams()는 주소에 입력된 파라미터 값을 가져올 때 사용한다.
문법까지 살펴보았으니 이제 본격적으로 코드를 작성해 보자!
import './App.css';
import { Navbar, Container, Nav, Row, Col } from 'react-bootstrap';
import { useState } from 'react';
import data from './data.js';
import { Route, Routes, Link, useNavigate, Outlet } from 'react-router-dom';
import Detail from './routes/Detail.js';
function App() {
let [shoes] = useState(data);
let navigate = useNavigate();
return (
<div className="App">
<Navbar bg="light" variant="light">
<Container>
<Navbar.Brand href="#home">HyeonShop</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={
<>
<div className='main-bg'></div>
<Container>
<Row>
{
shoes.map((a, i) => {
return (
<Card shoes={shoes[i]} i={i} />
)
})
}
</Row>
</Container>
</>
} />
<Route path='/detail/:id' element={<Detail shoes={shoes} />} />
<Route path='/about' element={<About />}>
<Route path='member' element={<div>회사 직원 정보</div>}></Route>
<Route path='location' element={<div>회사 위치 정보</div>}></Route>
</Route>
</Routes>
</div>
);
}
function About() {
return (
<div>
<h4>회사 정보</h4>
<Outlet></Outlet>
</div>
)
}
function Card(props) {
return (
<Col sm>
<img src={'https://codingapple1.github.io/shop/shoes' + (props.i + 1) + '.jpg'} width='80%' />
<h4>{props.shoes.title}</h4>
<p>{props.shoes.content}</p>
<p>{props.shoes.price}</p>
</Col>
)
}
export default App;
import { useParams } from "react-router-dom";
function Detail(props) {
let {id} = useParams();
let item = props.shoes.find(function(x){
return x.id == id
})
let itemId = parseInt(id)+1;
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={"https://codingapple1.github.io/shop/shoes"+itemId+".jpg"} width="100%" />
</div>
<div className="col-md-6">
<h4 className="pt-5">{item.title}</h4>
<p>{item.content}</p>
<p>{item.price}원</p>
<button className="btn btn-danger">주문하기</button>
</div>
</div>
</div>
)
}
export default Detail;
이렇게 /detail/상품아이디
로 접속하면 해당 상품의 정보를 볼 수 있는 상세 페이지가 나온다. 👍