패스트캠퍼스 메가바이트스쿨 Day 33 (7주차 수요일) - React로 쇼핑몰 만들기(2)

ctaaag·2022년 5월 27일
0
post-thumbnail

Today Topic : React로 쇼핑몰만들기(2)


🗝 Keywords

✅ react-router 기본개념 및 설치

✅ navigate,nested routes, outlet

✅ react-router로 제품 상세페이지 만들기



1. react-router 기본개념 및 설치

react-router는 왜 사용하는가?

  • react-router는 싱글페이지 어플리케이션인 리액트의 장점을 편리하게 만들어주는 라이브러리이다.
  • 각각의 페이지를 구분하고 이동할 때 도움을 준다.
  • react-router에는 코어를 모두 포함하고 있고, v4 버전 이후에는 웹 개발자용 react-router-dom과 앱개발자용 react-router-native로 나뉘어서 릴리즈 되고 있다.
  • 현재 웹을 개발 하고 있기 때문에 react-router-dom을 설치하고 진행할 예정

react-router-dom 기본 설정

import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store = {store}>
    <React.StrictMode>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </React.StrictMode> 
  </Provider>
);
  • index.js 파일에 를 선언하고 앱을 감싸고 import를 해주면 된다.

Routes,Route만들기

import {Routes, Route, Link} from 'react-router-dom'
<ComponentNavbar/>
<Routes>
  <Route path="/" element={}/>
  <Route path="/detail" element={<div>상세페이지임</div>}/>
  <Route path="/about" element={<About/>}>
</Routes>
  • 부모 요소에 Routes를 선언하고, Route라는 컴포넌트를 만들면 새로운 페이지가 만들어짐
  • path는 해당 홈페이지의 경로를 이야기하고, element는 해당 홈페이지에 들어가면 보여질 컴포넌트를 이야기함
  • 메인페이지는 "/"하나만 있으면 메인페이지임
  • 만약 라우터로 페이지를 이동해도 navbar처럼 계속 남아있어야하는 컴포넌트가 있다면 Route위나 아래에 독립적으로 넣어주면 됨.
  • 페이지도 컴포넌트를 만들면 좋음.

Link 태그로 이동하기

import {Routes, Route, Link} from 'react-router-dom'
<ComponentNavbar/>
<Link to ="/"></Link>
<Link to ="/detail">상세페이지</Link>
<Routes>
  <Route path="/" element={}/>
  <Route path="/detail" element={<div>상세페이지임</div>}/>
  <Route path="/about" element={<About/>}>
</Routes>
  • 위와 같이 Link를 만들면 해당 페이지로 클릭하면 넘어갈 수 있는 버튼이 만들어짐


2. navigate,nested routes, outlet

navbar에 Link 적용하기(useNavigate)

import {useNavigate,Outlet,useParams} from "react-router-dom";
export default function ComponentNavbar() {
  let navigate = useNavigate();
<Nav.Link onClick={() => {navigate("/");}}></Nav.Link>
<Nav.Link onClick={() => {navigate("/detail");}}>상세페이지</Nav.Link>
<Nav.Link onClick={() => {navigate("/cart");}}>장바구니</Nav.Link>
<Nav.Link onClick={() => {navigate(-1);}}>이전페이지</Nav.Link>
<Nav.Link onClick={() => {navigate(-1);}}>이전페이지</Nav.Link>
  • navigate를 사용하고 싶은 컴포넌트 내에서 useNavigate훅을 import하고 함수 안에서 해당 훅을 선언함.
  • Nav 엘리먼트에서 onClick 함수 만들어서 선언한 훅에 위와같이 해당 홈페이지 경로를 작성하면 해당 홈페이지로 이동하게 됨
  • 이전페이지로 이동하고 싶다면, -1이라는 경로를 만들어주면 이동하게 됨.

404 페이지 만들기

<Route path="*" element={<div>없는페이지요</div>}/>
  • 부모컴포넌트에서 Routes안에 route path로 "*" 을 입력하면 위에 path에 적힌 페이지 외의 모든 것을 이야기함.
  • 따로 path를 한 페이지 외에는 따로 만들어둔 것이 없기 때문에 해당 페이지에는 404페이지 관련 안내를 적을 수 있음.
import { Navigate } from "react-router-dom";
<Route path="/hi" element={<Hi />} />
<Route path="*" element={<Navigate to="/hi" replace />} />
  • 404페이지에서 특정 홈페이지 주소로 넘어가고 싶다면 Navigate to를 사용할 수 있음.
  • 만약 404페이지에 갔다가 뒤로가기버튼을 눌러서 초기 페이지로 이동을 하고 싶다면 replace를 꼭 사용해야함

nested Route와 Outlet

<Route path="/about" element={<About/>}>
  <Route path="member" element={<div>멤버임</div>}/>
  <Route path="location" element={<div>로케이션임</div>}/>
</Route>

<Route path="/about" element={<About/>}>
<Route path="/about/member" element={<div>멤버임</div>}/>
<Route path="/about/location" element={<div>로케이션임</div>}/>
</Route>
  • 만약 Route안에 Route를 만들어서 상세 페이지나 배너같은 것들을 보여주고 닫고 하고 싶다면?
  • 아래에 있는 Route와 위에 있는 Route path는 같다. 즉, 해당 컴포넌트안에 종속되는 컴포넌트를 만들고 싶을 때는 path를 따로 만들어줄 수 있지만, route의 자식컴포넌트로 만들어주면 간단하게 만들 수 있음
  • 이렇게 컴포넌트에 자식요소로 만들어주는 것을 nested Route라고 부른다.

Outlet

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

<Route path="/about" element={<About/>}>
  <Route path="member" element={<div>멤버임</div>}/>
  <Route path="location" element={<div>로케이션임</div>}/>
</Route>

<Route path="/about" element={<About/>}>
<Route path="/about/member" element={<div>멤버임</div>}/>
<Route path="/about/location" element={<div>로케이션임</div>}/>
</Route>

const About = () => {
  return (
    <div>
      <h4>회사정보임</h4>
      <Outlet></Outlet>
    </div>
  )
}
  • 그런데 만약에 nested Route에 부모 element와 자식 element를 같이 보여주고 싶을 때는 어떻게 할 수 있을까?
  • 해당 기능을 간편하게 해주는 것이 바로 Outlet이다. 부모 엘리먼트에 outlet을 적어주면 해당 자식 컴포넌트들이 보이게 됨
  • 따라서 nested Route는 모달창을 보여주거나 탭 ui를 만드는 등 새로운페이지인데 일부 요소만 바뀐 페이지를 기획할 때 사용할 수 있음.
const About = () => {
  let navigate = useNavigate()
  return (
    <div>
      <h4>회사정보임</h4>
      <div onClick={()=>{navigate("/about/member");}}> 멤버 보여주세요</div>
      <div onClick={() => {navigate("/about/location");}}> 로케이션 보여주세요</div>
      <Outlet></Outlet>
    </div>
  )
}
  • 위와 같이 어떤 버튼을 클릭시 보여주려면 h4에 onclick navigate 설정해서 하위 페이지로 이동 후, outlet을 부모요소에 설정을 해주면 해당 페이지를 열었다 닫았다 할 수 있음.


3.react-router로 제품 상세페이지 만들기

props 활용한 상세페이지 만들기

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

unction Detail(props) {
  return (
  <img src={process.env.PUBLIC_URL + `${props.product[0].image}`}></img>
  <div>{props.product[0].price}</div>
  <div>{props.product[0].title}</div>
  <button>결제하기</button>
  )
}
  • 이렇게 props를 활용하면 해당 내용의 상세페이지를 불러올 수 있음
  • 근데 여기서 문제는 상세페이지 각각의 데이터를 눌렀을 때마다 바뀌게 해주는 기능을 추가해야만 100개가 넘는 상세페이지를 만들더라고 간편하게 만들 수 있음

페이지를 여러개 만드는 방법(useParams)

  • 이런 문제를 해결하기 위해서는 상세페이지를 만드는 컴포넌트에서 각 항목마다의 id 값을 불러와서 적용할 수 있어야함
  • 이렇게 하기 위해서는 아래와 같은 절차로 useParams를 이용해서 id 값을 불러올 수 있다.

부모 루트에 :id를 부여하기

<Route path="/detail/:id" element={<Detail product={product}/>} />
  • 부모 루트에 path로 id를 설정하게 되면 detail뒤에 어떤 변수가 와도 상세페이지로 넘어가게 된다.
  • 그렇다면 무한개의 상세페이지는 만들어진 셈이지만, 모두 동일한 상세내용이 나올 것
  • 이후에는 id 값에 맞춰서 데이터를 넣어줘야함.

해당 id에 맞게 데이터 넣어주기

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

export default function Detail(props) {
  let { id } = useParams();
  if (id < props.product.length) {
    return (
      <>
        <img
          src={process.env.PUBLIC_URL + `${props.product[id].image}`}
          width={"50%"}
</img>
        <div>{props.product[id].price}</div>
        <div>{props.product[id].title}</div>
        <button>결제하기</button>
      </>
    );
  } else {
    return <div>잘못된 페이지입니다</div>;
  }
}
  • 해당 컴포넌트에서 useParams를 import하고 id를 hook을 통해 선언해주면, 해당 통해 id 불러오기
  • 예를 들어 /detail/0 하면 0번째 데이터, /detail/1하면 1번째 데이터가 들어가게끔 해주면 됨
  • 이를 props를 통해 구현해주면 됨.
  • 이 때, /detail/304 나 /detail/아무문자 이런식으로 데이터가 없는 페이지로 이동되었을 때 특정값을 보여주고 싶다면 if문을 통해서 return을 해주면 됨
    -아래에서 보듯이 url에 따라 다른 데이터들이 들어감


제품 컴포넌트에 click이벤트 부여하기

  • 자 그러면 모두 준비가 되었으니, 이제 제품을 클릭했을 때 해당 url로 넘어가기만 하면 끝남.
  • 이를 위해서는 useNavigate를 통해서 해당 이미지에 온클릭 이벤트를 넣어주면 됨.
import { useNavigate } from "react-router-dom";

export default function Product(props) {
  let navigate = useNavigate();
  const cardTotal = props.product.map((a, i) => {
    return (
      <Col id="i" key={i}>
        <img
          src={process.env.PUBLIC_URL + `${props.product[i].image}`}
          width={"80%"}
          onClick={() => {
            navigate(`/detail/${i}`);
          }}
</img>
        <h4>{props.product[i].title}</h4>
        <p>{props.product[i].content}</p>
      </Col>
    );
  });
  return (
    <Container>
      <Row>{cardTotal}</Row>
    </Container>
  );
}
  • 위와 같이 맵 함수로 제품 컴포넌트들이 자동으로 만들어지는데 이 때 이미지에 온클릭이벤트로 navigate(/detail/${i})를 통해서 각 이미지 값에 고유한 onClick을 부여할 수 있음

데이터가 바뀌어도 id로 해당 데이터를 끌어오려면?

  let { id } = useParams();
  let 찾은상품 = props.shoes.find(function(x){
    return x.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>  
  )
};
  • 찾은 상품이라는 변수에 find를 통해 해당 id값이 같을 경우에 돌려주는 함수를 할당하고
  • 해당 변수.title 등 이런 식으로 값을 찾아서 넣어줄 것.
profile
프로그래밍으로 지속가능한 세상을 꿈꾸며

0개의 댓글