Hyebin‘s blog

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
filter() 함수, map()함수 사용해도 무관

 

답안에는 find() 라는 ES6 신문법을 사용하였는데, 이는 Array 안에서 원하는 자료를 찾고싶을 때 사용한다.

  1. find()는 array 뒤에 붙일 수 있으며, 안에 콜백함수 들어간다.
  2. 콜백함수 내의 파라미터는 array 안에 있던 하나하나의 데이터를 의미
  3. return 오른쪽엔 조건식 가능
  4. 현재 URL의 /:id에 적힌 값과 상품의 영구번호가 같은지 비교
profile

Hyebin‘s blog

@hyebin Lee

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그