Studying/React

리액트 기초부터 쇼핑몰 프로젝트까지! Part2 #2 리액트라우터

코뿌 2023. 4. 28. 16:05

* 페이지 나누기

: 리액트는 single page application라서 index.html 이라는 하나의 html 파일만 사용하기 때문에 react-router-dom이라는 외부 라이브러리 설치해서 사용함.

 

 

* 라우터로 페이지 나누는 법

1. react-router-dom 설치

 

1) 터미널 열고  npm install react-router-dom@6 입력해서 설치 한 뒤

 

2) index.js 파일로 가서 import 한 뒤 하단과 같이 <App/> 을 <BrowserRouter>로 감싸줌.

import { BrowserRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <BrowserRouter>
        <App />
      </BrowserRouter>
  </React.StrictMode>
);

 

2. 상단에 여러가지 컴포넌트( Routes, Route, Link )를 import한 뒤

 

3. <Routes>를 만들고 그 안에 <Route> 작성

: Route는 각각의 페이지를 나타냄.

4. <Route path="/url경로" element={ <보여줄html> }  /> 작성

// ( App. js ) 에서



import { Routes, Route, Link } from 'react-router-dom'


function App() {
  let [shoes] = useState(data)
  return (
    <div className='App'>

      <Routes>
        <Route path="/" element={ <div>메인페이지</div> } />
        <Route path="/detail" element={ <div>상세페이지</div> } />
       
      </Routes>

 

 

* 페이지 꾸미기

- 메인페이지 꾸미기

: 상품목록과 브랜드 대문사진이 보이게 만들어주기

function App() {
  let [shoes] = useState(data)
  return (
    <div className='App'>
    <Navbar bg="dark" variant="dark" className="name">
        <Container>
          <Navbar.Brand href="#home" className="brandName">LERB</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="#home">our story</Nav.Link>
            <Nav.Link href="#features">shopping</Nav.Link>
            <Nav.Link href="#pricing">contact</Nav.Link>
          </Nav>
        </Container>
      </Navbar>
   
   <Routes>
    <Route path="/" element={ 
   <>
   <div className='main-bg'></div> {/*대문사진*/}
   <div className='container'>
   <div className='row'>
   {
    shoes.map(function(a,i){
      return (
        <Information shoes={shoes[i]} b={i+1}></Information>
      )
    })
    }
    </div>
    </div> 
    </> }/>
        <Route path="/detail" element={<div>상세페이지임</div>} />       
      </Routes>



   </div>
  );
}

 

- 페이지를 component로 만들기

function App() {
  let [shoes] = useState(data)
  return (
    <div className='App'>
    <Navbar bg="dark" variant="dark" className="name">
        <Container>
          <Navbar.Brand href="#home" className="brandName">LERB</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="#home">our story</Nav.Link>
            <Nav.Link href="#features">shopping</Nav.Link>
            <Nav.Link href="#pricing">contact</Nav.Link>
          </Nav>
        </Container>
      </Navbar>
   
   <Routes>
    <Route path="/" element={ <Main b="i" shoes={shoes}></Main> }/>
    <Route path="/detail" element={<Detail></Detail>} />       
      </Routes>



   </div>
  );
}

function Information(props) {
  return(
   <div className='col-md-4'>
          <img src={"https://codingapple1.github.io/shop/shoes"+ props.b + ".jpg"} width="80%" />
          <h4>{props.shoes.title}</h4>
          <p>{props.shoes.price}</p>
        </div>
  )
  }


function Main(props){
  return(
<>
   <div className='main-bg'></div> {/*대문사진*/}
   <div className='container'>
   <div className='row'>
   {
    props.shoes.map(function(a,i){
      return (
        <Information shoes={props.shoes[i]} b={i+1}></Information>
      )
    })
    }
    </div>
    </div> 
    </> 
  )
}

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%" />
    </div>
    <div className="col-md-6">
      <h4 className="pt-5">상품명</h4>
      <p>상품설명</p>
      <p>120000원</p>
      <button className="btn btn-danger">주문하기</button> 
    </div>
  </div>
</div> 
  )
}

 

- detail component를 file로 분리하기

src 폴더 밑에 pages 라는 폴더를 만들고 Detail.js라는 파일을 생성함.

그 안에 component안에 있던 내용을 붙여 넣은 뒤 export default Detail; 해주고

app.js 가서 import Detail from './pages/Detail.js'; 입력.

 

 

* 페이지 이동 버튼 만들기

: 유저들은 주소창에 url 직접 입력해서 들어가지 않고 링크타고 들어가니까 링크를 만들어줘야됨

 

react-router-dom에서 Link 컴포넌트 import해오고 원하는 곳에서 <Link> 사용.

import { Link } from 'react-router-dom'

<Link to="/">홈</Link>
<Link to="/detail">상세페이지</Link>

-> 이거 못 생겨서 쓰기 싫으면 useNavigate() 사용하면 됨.

 

* 새로운 컴퍼넌트 추가

import { Routes, Route, Link, useNavigate, Outlet } from 'react-router-dom'

 

* useNavigate 

: 페이지 이동을 도와주는 함수가 들어있는 hook

let navigate = useNavigate()

// navigate 변수에다가 useNavigate를 저장해두고 나중에 씀

사용할 때는 onClick 했을 때 useNavigate가 저장된 navigate변수를 사용함

navigate('/detail') 이런 코드 실행하면 /detail 페이지로 이동함.

navigate(2) 숫자 넣으면 앞으로 2번 가기 

-1 넣으면 뒤로 1번 가기

 

function App() {
  let [shoes] = useState(data)
  let navigate = useNavigate();

  return (
    <div className='App'>
    <Navbar bg="dark" variant="dark" className="name">
        <Container>
          <Navbar.Brand onClick={()=>{ navigate('/') }} className="brandName">LERB</Navbar.Brand>
          <Nav className="me-auto">
            <Nav.Link href="#home">our story</Nav.Link>
            <Nav.Link href="#features">shopping</Nav.Link>
            <Nav.Link onClick={()=>{ navigate('/detail')}}>Detail</Nav.Link>
          </Nav>
        </Container>
      </Navbar>

 

 

* 404 page

: 잘못된 경로로 접속했을 때 없는 페이지라는 걸 알려주는 페이지

 

<Route path="*" element={<div>없는 페이지유</div>} />

// path="*" 는 위에 만들어둔 경로 외의 모든 것

 

 

* Nested Routes

: 페이지 안에 들어가있는 페이지. 라우터 안에 둥지튼 라우터. 서브경로를 만들 수 있음.

 

<Route path="/about/member" element={ <div>멤버들</div> } />
<Route path="/about/location" element={ <div>회사위치</div> } />

==

<Route path="/about" element={ <About/> } >  
  <Route path="member" element={ <div>멤버들</div> } />
  <Route path="location" element={ <div>회사위치</div> } />
</Route>

<Route>안에 <Route>를 넣은 것.

/about/member로 접속하면 <About> 과 <div>멤버들</div> 모두가 보임.

두 element 모두 표시할 수 있음.

 

About 함수 만들기

function About(){
  return (
    <div>
      <h4>about페이지임</h4>
      <Outlet></Outlet>
    </div>
  )
}

 

<Outlet>은 nested routes안의 element들을 어디에 보여줄지 표기하는 곳

( element 를 둘 다 보여줘야되니까 안에 있는 route가 어디에서 보이면 좋을지 정하는 것)

 

장점

동적인 UI를 만들 수 있음

뒤로가기 버튼을 이용할 수 있음

 

 

* Detail 페이지를 꾸며보자

: app.js에서 props로 받아온 데이터를 사용하여 상품명 데이터를 받아옴.

 

App.js 안에 <Detail> 쓰는 곳에서 props 전송

// (App.js) 에서


function App() {
  let [shoes] = useState(data)
  let navigate = useNavigate();

  return (
 

   <Routes>

    <Route path="/" element={ <Main b="i" shoes={shoes}></Main> }/>
    <Route path="/detail" element={<Detail shoes={shoes} />} /> 
    <Route path="*" element={<div>없는 페이짐둥</div>} />     
      
      </Routes>



   </div>
  );
}

 

 

Detail.js에서 props로 받아온 state 이용하기

<h4 className="pt-5">상품명</h4>

// 상단을 하단처럼 props로 받아온 데이터 이용

<h4 className="pt-5">{props.shoes[0].title}</h4>

 

상단의 내용을 하단에 추가하여 완성

// (Detail.js)

import { propTypes } from "react-bootstrap/esm/Image";

function Detail(props) {
    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">
        <h4 className="pt-5">{props.shoes[0].title}</h4>
        <p>상품설명</p>
        <p>120000원</p>
        <button className="btn btn-danger">주문하기</button> 
      </div>
    </div>
  </div> 
    )
  }

  export default Detail;

 

나머지 데이터도 props로 받아온 data를 이용하여 데이터 받아옴.

function Detail(props) {
    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">
        <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> 
      </div>
    </div>
  </div> 
    )
  }

-> 이렇게 하면 detail페이지에 0번 상품만 나옴.

 

 

* URL parameter

: route 여러 개 만들어 페이지를 여러 개 만들 때 사용.

path="/detail/:url파라미터" 

그래서 위의 <Route>는 /detail/아무거나 입력하면 <Detail>컴포넌트 보여달라는 뜻.

아무거나 자리에 진짜 말그대로 아무거나 입력해도 항상 <Detail> 컴포넌트를 보여줌.

-> /detail/ 이 뒤에 뭘 입력하든 페이지마다 똑같은 내용을 보여줌

 <Route path="/detail/:id" element={<Detail shoes={shoes} />} />

 

 

* useParams()

: /:파라미터 자리에 유저가 입력한 값을 가져올 수 있음. 페이지마다 다른 내용을 보여줄 때 사용

 

- 유저가 파라미터 자리에 입력한 숫자마다 페이지를 다르게 설정

[0] 자리에 [id]를 써서 url에  detail/2 이런 식으로유저가 입력한 숫자를 불러와서 2번 상품을 보여주는 페이지를 설정.

<h4 className="pt-5">{props.shoes[0].title}</h4>
// (Detail.js)


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/shoes1.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> 
    )
  }

 

 

* Styled-component

 

설치방법

터미널 열고 - npm install styled-components 입력

 

Detail.js 에 import

import styled from 'styled-components'