04.React Router

Updated:


1.React Routing 이해하기

  • 전통적인 방식인 browser 에서 sever로 무언가 페이지를 요청하는 방식은 URL 의 단위를 바탕으로 server 에 해당 페이지 정보를 받아와서 브라우저에 보여주는 방식임

image

  • React 로 넘어 오면서 한번에 모든 페이지 정보를 가져온 후, 내부에서 URL 에 맞춰서 화면을 보여주는 과정임

image

SPA 라우팅 과정

1.브라우저 최초에 ‘/’ 경로로 요청을 하면 (root 경로)

2.React Web App 을 내려 줍니다. (서버에서)

3.내려받은 React App 에서 ‘/’ 경로에 맞는 컴포넌트를 보여줍니다. (브라우저에서)

4.React App 에서 다른 페이지로 이동하는 동적을 수행하면,

5.새로운 경로에 맞는 컴포넌트를 보여줍니다

2.SetUp

  • 사이트에 상세 페이지 (페이지 나누기) 를 하기 위해서 react-router-dom 라이브러리를 이용함

설치

$ yarn add react-router-dom
  • CRA 에 기본 내장된 패키지가 아닙니다

  • react-router-dom 은 Facebook 의 공식 패키지는 아닙니다.

  • 가장 대표적인 라우팅 패키지 입니다.

세팅

  • index.js 파일가서 설치된 package 를 import 해줍니다
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      {" "}
      // BrowserRouter tag 를 App 에 감싸서 세팅 합니다.
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

BrowserRouter vs HashRouter

  • HashRouter 는 좀더 안전하게 라우팅 할 수 있게 도와줌 주소창에 # 기호를 입력해서 구분해줌. 사이트 주소 뒤에 # 이 붙는데 # 뒤에 적는 적은 서버로 전달 하지 않음

  • BrowserRouter 는 라우팅을 리액트가 아니라 서버에게 요청할수도 있어서 위험할 수 있음 그래서 서버에서 서버 라우팅을 방지하기 위해서 API 를 따로 작성해줘야 함

Route 를 만들기 (페이지 나누기)

// in App.js

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

// 처음 main / 경로는 exact 를 사용해서 정확하게 / 것만 path 로 사용하기 위해 반드시 설정
<Route exact path="/">
  <div>main page</div>
</Route>
// 나머지 페이지는 path 에 맞게 localhost/detail 같이 접속이 됨
<Route path="/detail">
  <div>detail page</div>
</Route>

// HTML 코드 말고 component 를 route 해주는것 modal 은 component 이름
<Route path="/경로" component={modal}></Route>

3.Dynamic 라우팅

  • 개발을 하다보면 url 을 고정적으로 하지 않고 동적으로 처리해서 어떠한 값을 받아와서 component 에서 보여 준다던가, 그 값을 이용해 어떠한 로직을 돌린다던가, 이러한 일들을 하기 위해 dynamic routing 이 필요하게 됨

예를 들어 /profile/1 이라고 특정 페이지를 추가할때 1, 2, 3 계속해서 dynamic 페이지를 생성하려면 아래와 같이 주로 설정 함

// App.js

<Route path="/profile/:id" component={Profile} />
// in profile.jsx
// 여기서 console.log(props) 하게 되면

import React from "react";
export const Profile = (props) => {
  console.log(props);
  return <div>Profile 페이지 입니다</div>;
};

image

path 부분에서 :id 를 지정한 후에 해당 {profile} component 를 만들어서 사용할 수 있습니다. (주의: id 값은 type 이 string 이 됨)

// in Profile.jsx

import React from "react";
export const Profile = (props) => {
  const id = props.match.params.id;
  console.log(id, typeof id);
  return (
    <>
      <h2>Profile 페이지 입니다.</h2>
      {id && <p>id 는 {id} 입니다.</p>}
    </>
  );
};

image

dynamic routing with query string

  • 예제 url localhost:3000/about?name=jacob 이런식으로 정보가 포함되는 dynamic routing 만들기 (optional 한 값을 추가하기)

URLSearchParams 를 사용하기

MDN URLSearchParams

import React from "react";

export const About = (props) => {
  // props 의 데이터 불러오기
  const searchParams = props.location.search;
  console.log(searchParams);

  // new obj 객체 생성
  const obj = new URLSearchParams(searchParams);

  //  name 의 value 값 추출
  console.log(obj.get("name"));
  return <div>About 페이지 입니다.</div>;
};

image

  • 단점: URLSearchParams 의 method 를 기억하고 사용해야 합니다 / URLSearchParams 가 browser 의 내장 객체이기 때문에 browser 에 따라서 지원하지 않는 경우도 있습니다. (Internet Explore 는 아예 지원 안함)

query-string 라이브러리 사용하기

query-string github

# 설치
$ yarn add query-string
import React from "react";
// import queryString
import queryString from "query-string";

export const About = (props) => {
  const searchParams = props.location.search;
  console.log(searchParams);

  //  queryString.parse() 를 통해서 queryString 추출
  const query = queryString.parse(searchParams);
  console.log(query);
  return (
    <>
      <h2>About 페이지 입니다.</h2>
      {query.name && <p> name 은 {query.name} 입니다. </p>}
    </>
  );
};
  • 기존의 a tag 를 사용하게 되면 페이지가 변경될때마다 sever 에서 data 를 가져 오기 때문에 react 의 특성이 반영 되지 않은 link 이기 때문에 react router dom 의 Link component 를 사용해서 해당 페이지를 이동하게 할 수 있음

  • 지금 이동하고자 맞는 경로를 찾는것임

  • React router 를 활용해서 Link 버튼 만들기

image

  • import {NavLink} from 'react-router-dom';

  • activeClassName, activeStyle 처럼 active 상태에 대한 스타일 지정이 가능합니다.

  • Route 의 path 처럼 동작하기 때문에 exact 가 있습니다.

  • 일단 안의 버튼에 href 버튼 지우고, 버튼병</Link> 식으로 Link 기능을 통해서 path 와 연결합니다

// 예시..
<Nav.Link> <Link to="/">Home</Link></Nav.Link>
<Nav.Link> <Link to="/detail">Detail</Link></Nav.Link>

4-2. History

  • Link 말고 만약 button 을 눌렀을 경우 페이지를 이동 시키는 방법 (예. 뒤로가기 버튼, 특정 경로로 이동 버튼 만들기)

    • useHistory 라는 hook 을 import

    • useHistory() hook 사용

// 버튼을 클릭하면 뒤로가기 가 작동
<button className="btn btn-danger">주문하기</button>
  <button className="btn btn-primary" onClick={() => {
    history.goBack();
  }}>뒤로가기</button>

// 특정
<button className="btn btn-danger">주문하기</button>
  <button className="btn btn-primary" onClick={() => {
    history.push('/');
  }}>홈으로 가기</button>

4-3. Switch

  • Switch component 를 사용하게 되면 여러개가 맞아도 하나만 보여 달라는 의미가 됨

  • 모든 로 감싸게 되면 여러가지 중에서 하나만 선택에서 보여달라는 의미인것임

  • 중복 페이지 연결을 막기위해서 대부분 code 에서는 로 감싼다음에 사용합니다

  • 여러 Route 중 순서대로 먼저 맞는 하나만 보여줍니다.

  • exact 를 뺄 수 있는 로직을 만들 수 있습니다.

  • 가장 마지막에 어디 path 에도 맞지 않으면 보여지는 컴포넌트를 설정해서, “Not Found” 페이지를 만들 수 있습니다.

// in App.js

// Switch 를 사용해서 가장 큰 범위인 / Home 이 맨아래로 가고 좁은 범위의 순서대로 위에서부터 진행 하면 exact 를 쓰지 않고도 정확하게 경로 설정을 할 수 있음 (단, 맨아래  / 는 exact 를 써줘야 함)
function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/profile/:id" component={Profile} />
        <Route path="/profile" exact component={Profile} />
        <Route path="/about" component={About} />
        <Route path="/" exact component={Home} />
        {/* 위에서 걸리지 않는 경로가 되기 때문에 Page NotFound 를 사용할 수 있음 */}
        <Route component={NotFound} />
      </Switch>
    </BrowserRouter>
  );
}

image

5.URL parameter

  • 참고!! 중요한 data 는 App.js 에 보관하는것을 권장한다. 왜 (그래서 하위 js 파일에서 data 를 사용할때 data biding 을 사용해서 props 로 가져와서 사용하는것을 권장함)

  • 그래서 나중에 redux 에 파일을 보관해서 사용하면 상태관리가 훨씬 용이하게 됨

상세페이지 추가로 만들기

예시로..

  • /detail/0 접속하면 0번째 상품을 보여주고
  • /detail/1 접속하면 1번째 상품을 보여주고
  • /detail/2 접속하면 2번째 상품을 보여주고

하는식의 routing page 을 추가 하는 방법임

  • /detail/:id 는 아무 문자나 받겠다는 URL 작명법

    • 콜론 뒤에는 맘대로 작명

    • 여러개 사용도 가능함

// App.js

{
  /* parameter 를 사용하는것 :id 명은 아무거나 해도 됨 */
}
<Route path="/detail/:id">
  <Detail shoes={shoes} />
</Route>;
// in Detail.js

//  URL 추가를 위해 usePrams import
import { useHistory, useParams } from 'react-router-dom'

// 라우터의 useParams hook : parameter 값을 변수로 만들어서 사용하는 방법
let { id } = useParams(); // app.js 에서 path의 :id 값을 가져감


// 이런식으로 shoes[id] 값에 각 id 값이 할당되서 해당되는 data 의 페이지가 나타나게 됨

<div className="col-md-6 mt-4">
  <h4 className="pt-5">{ props.shoes[id].title }</h4>
    <p>{ props.shoes[id].content}</p>
    <p>{ props.shoes[id].price}</p>
</dic>

  • 🔶 근데 Data 의 순서가 바뀐다면 상세페이지도 이상해짐 (예를 들어 상품 페이지를 가나다 순에서 가격순으로 정렬할 경우에 )

    • 그럴경우에는 data의 영구번호를 활용해서 routing 을 해줘야 한다. 즉 data 의 id 명이나 고유 번호를 사용해서 위에처럼 순서로 data 를 나열하면 안됨
let { id } = useParams(); // app.js 에서 path의 :id 값을 가
let findGood = props.shoes.find(good => good.id == id)
// 화살표 함수는 parameter 가 1개 일경우에 () 와 {return} 생략 가능

<div className="col-md-6 mt-4">
  <h4 className="pt-5">{findGood.title }</h4>
    <p>{ findGood.content}</p>
    <p>{ findGood.price}</p>
</div>

설명:

  • find() 를 사용해서 array 안에 원하는 자료를 찾고 싶을 때 사용함

  • find()는 array 뒤에 붙일 수 있으며, 안에 콜백함수가 들어갑니다.

  • 콜백함수 내의 파라미터는 (위에선 good) array 안에 있던 하나하나의 데이터를 의미합니다.

  • return 오른쪽엔 조건식을 적을 수 있습니다. 이게 참인 데이터만 새로운 변수에 저장해줍니다.

  • 조건식엔 그리고 그걸 현재 URL의 /:id에 적힌 값과 상품의 영구번호 (good).id)가 같은지 비교하고 있는 겁니다.

그래서 /detail/0으로 접속시 찾은상품이라는 변수를 출력해보시면 아마 영구번호가 id : 0인 데이터가 나올겁니다.

/detail/1로 접속시 찾은상품이라는 변수는 영구번호가 id : 1인 데이터일겁니다.

그래서 찾은상품이라는 변수를 이용해서 상품명, 가격 HTML 부분에 데이터바인딩을 했을 뿐입니다.

실제 개발할 땐 그냥 서버에 id : 0인 상품데이터를 Ajax 나 axios 로 요청하는 경우가 많아서 직접 find() 를 사용해서 id 값을 불러 올경우는 많지 않습니다.

🔶 🔷 📌 🔑

Reference

Categories:

Updated:

Leave a comment