[React] Router를 이용하여 페이지 이동

이다영·2024년 7월 2일

React

목록 보기
12/31

리액트는 Single Page Application 사용한다. 줄여서 SPA라고 한다.
SPA란 페이지 전체가 바뀌는 것이 아니라 필요한 부분만 업데이트를 하는 방식으로 페이지 새로고침이 되지 않는다 .

  • SPA는 빠르게 페이지 전환이 되는 장점이 있지만 단점도 있다.
    첫 화면의 로딩시간이 길고, 자바스크립트의 파일이 커진다

⭐ React-Router

  • 사용자가 입력한 주소를 감지하는 역할을 하며, 여러 환경에서 동작할 수 있도록 여러 종류의 라우터 컴포넌트를 제공한다. 라우터는 해당 URL에 맞는 페이지를 보여주는 것을 의미한다

⭐React Router(v6) 사용

  1. 설치 ➡️ npm install react-router-dom@6
  2. src -> index.js파일 -> <App />, <BrowserRouter>로 감싸주기
//index.js

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

root.render(
  <BrowserRouter>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </BrowserRouter>
);
  1. Routes, Route 상단에 import 해오기
import { Routes, Route } from "react-router-dom";

//리액트라우터 작성방법
<Routes>
<Route path="/detail/:id" element={<Detail />} />
</Routes>
  • 리액트 라우터 작성방법을 설명하자면 Routes 하위에 Route를 넣어야 하고, Route는 페이지를 의미한다. Route가 많아지면 많아질 수록 페이지가 늘어가는 것을 확인 할 수 있다.
  • 추가내용➕ path에 경로에 / 이렇게 적으면 메인페이지를 의미하고, * 이렇게 적으면 해당하는 URL 이 외에 모든 것을 의미하기 때문에 element 안에 <div>없는 페이지 입니다...</div> 이런식으로 해당 URL이 아닐 경우 보여지는 페이지를 따로 만들 수도 있다.
  • Route안에는 pathelement가 있는데 path=" " 안에는 파일 경로를 적어줄 수 있고,
    element={ } 안에는 페이지에 대한 내용을 html로 적을수도 있고, 컴포넌트화 해서 넣을 수도 있다
  • 리액트 라우터에는 Link 컴포넌트가 있다 각각 url 경로로 이동하는 링크를 설정해줄 수 있는데 화면에 렌더링 될 때는 기본값이 스타일을 안 준 <a>태그 처럼 표시 되기 때문에 UI가 예쁘지 않다. 보통은 UI를 먼저 만들고 useNavigate를 사용하는데 Link 컴포넌트 사용하는 방법을 먼저 살펴보면 ...
import { Routes, Route, Link } from "react-router-dom";

<Link to="/"></Link> //메인페이지 이동
<Link to="/detail">상세페이지</Link> //detail 상세페이지 이동

⭐ 버튼 클릭 시 페이지 이동 (useNavigate)

  • useNavigate는 페이지를 이동시켜주는 함수이다
  • navigate() 괄호안에는 숫자를 넣어줄 수 있는 데 1이면 앞으로 1번가기 -2면 뒤로 2번가기 이렇게 사용할 수도 있다
import { Routes, Route, Link, useNavigate } from "react-router-dom";

function App(){
  const navigate = useNavigate()
  
  return ( //버튼 클릭 시 detail페이지로 이동하기
   <button 
    onClick={()=>{ 
     navigate('/detail')  //detail페이지로 이동
   }}
  >
     detail 이동 버튼
   </button>
  )
}

⭐ 예제 풀이

//data.jsx

const data = [
  { //검정신발
    id: 1,
    title: "White and Black",
    content: "Born in France",
    price: `120,000`,
  },

  { // 빨강신발
    id: 2,
    title: "Red Knit",
    content: "Born in Seoul",
    price: `110,000`,
  },

  { //회색신발
    id: 3,
    title: "Grey Yordan",
    content: "Born in the States",
    price: `130,000`,
  },
];

export default data;
  • 객체로 3개의 신발 상품 데이터를 만들었다
//App.js

import { Route, Routes, useNavigate } from "react-router-dom";
import { Navbar, Container } from "react-bootstrap";

import "./App.css";
import data from "./data"; //3개의 신발 상품 데이터
import Card from "./components/Card";
import Detail from "./pages/Detail";

function App() {
  const navigate = useNavigate(); //페이지 이동을 도와주는 함수
  const shoes = data; //객체 data를 변수 shoes에 넣음

  return (
    <div className="App">
      <Navbar bg="light" variant="light">
        <Container>
          <Navbar.Brand
            onClick={() => {
              navigate("/");
            }}
          >
            ShoeShop {/** 메인로고버튼*/}
          </Navbar.Brand>
        </Container>
      </Navbar>
      <Routes>
        <Route // 메인페이지 Card부분
          path="/"
          element={
            <>
              <div className="main-bg"></div>
              <Container>
                <div className="row">
                  {shoes.map((item, i) => ( // 3개 신발 상품 데이터 반복생성
                    <Card item={item} i={i} key={i} />
                  ))}
                </div>
              </Container>
            </>
          }
        />
        <Route path="/detail/:id" element={<Detail shoes={shoes} />} /> // 상세페이지 Detail
      </Routes>
    </div>
  );
}

export default App;
  • 필요한 컴포넌트들을 import 해왔고, 위에서 부터 설명하자면 메인로고 버튼에 useNavigate를 사용해서 메인페이지로 이동할 수 있게 만들었다

  • Route로 페이지를 만들고, 메인페이지에 map을 사용하여 3개 상품을 반복생성하였다. 3개의 상품은 Card라는 컴포넌트 안에 데이터가 들어가 있다. Carditem을 넘겨준 이유는 상품명, 상품내용, 상품가격을 다 다르게 보여줘야 하기 때문에 프롭스로 item을 넘겨줬고, i를 넘겨준 이유는 상품 이미지를 다 다르게 보여줘야 하기 때문에 넣었다. 이렇게 반복생성을 할 때에는 key 값을 넣어줘야 오류가 안 난다

  • Routedetail 페이지를 만들고, 3개의 상품이 각각 클릭 됐을 때 detail페이지의 경로가 다 다르고 데이터도 달라야 하기 때문에 경로를 /:id로 만들어준 다음에 Detail컴포넌트를 컴포넌트화 해서 내용으로 넣어주었다. 프롭스로 shoes를 넘겨준 이유는 경로 id와 shoes(data)의 영구번호인 id를 비교해서 그에 맞는 내용과 이미지를 보여줘야 하기 때문에 넣었다

//Card.jsx

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

const Card = ({ item, i }) => {
  const navigate = useNavigate();

  return (
    <div className="col-md-4">
      <img
        src={"https://codingapple1.github.io/shop/shoes" + (i + 1) + ".jpg"}
        width="80%"
        alt=""
        onClick={() => navigate(`/detail/${item.id}`)} //id는 1, 2, 3
      />
      <h4>{item.title}</h4> 
      <h6>{item.content}</h6>
      <p>{item.price}</p>
    </div>
  );
};

export default Card;
  • 프롭스로 전달 받은 itemshoes와 같은 의미이다. 그래서 item.title을 하게되면 상품명이 잘 나타나는 것을 확인 할 수 있다. map에서 두번째 인자 i는 0부터 시작하는 정수이고, 즉 인덱스 번호로 표현할 수 있다.

  • 이미지 src i + 1에 대한 설명을 하자면 이미지는 1, 2, 3인데 i는 0부터 시작하기 때문에 +1을 해준 것이다

  • onClick으로 navigate를 이용해 URL 경로를 적어주었다. (/detail/${item.id}) 이 경로에서 item.id는 영구번호로 1, 2, 3의 값이 각각 들어있다 이미지 클릭 시 경로가 달라야 하기 때문에 영구번호로 넣어준 것이다 사실상 저 코드의 의미는 shoes.id와도 같은 의미인 걸 확인 할 수 있다 프롭스로 item을 받아왔기 때문에 item을 쓴 것이다

//Detail.jsx
import { Container } from "react-bootstrap";
import { useParams } from "react-router-dom";

const Detail = ({ shoes }) => {
  const { id } = useParams();
  const products = shoes.find((product) => product.id === Number(id));

  return (
    <Container>
      <div className="d-flex justify-content-center">
        <div className="col-md-8">
          <img
            src={
              "https://codingapple1.github.io/shop/shoes" + products.id + ".jpg"
            }
            width="80%"
            alt=""
          />
          <h4>{products.title}</h4>
          <h6>{products.content}</h6>
          <p>{products.price}</p>
          <button className="btn btn-danger">주문하기</button>
        </div>
      </div>
    </Container>
  );
};

export default Detail;
  • path="/detail/:id" URL 경로에 iduseParams로 가져왔다 URL idshoes의 영구번호 id를 비교해서 그에 맞는 데이터만 보여지게 하기위해 find 메서드를 사용했다 이때 ==과 ===의 차이점을 정확히 알 수 있게 되었는데 URL id는 문자열이고, shoes의 id는 숫자였다 그렇기 때문에 두개를 비교하면 당연히 오류가 날 수 밖에 없다 그래서 URL idNumber 또는 parseint를 사용해서 숫자로 바꿔주게 되면 오류가 해결된다

출처

코딩애플 리액트
리액트라우터 사용하기

0개의 댓글