• React

[React] Router

man_on 2021. 10. 24. 16:53
반응형

 

 

React Router?

 

 

SPA의 routing문제를 해결하기 위해 사용되는 네비게이션 라이브러리이다. 

React Router를 사용하면 앱에서 발생하는 라우팅이 location이나 history와 같은 브라우저 내장 api와 완벽하게 연동이 된다.

 

 

 

> setting

npm install react-router-dom

 

 

<BrowserRouter> vs <HashRouter>

: HashRoutersms URL 맨뒤에 /#/이 붙은채로 시작한다.

  왜? 

  원래 브라우저 주소창에 페이지 입력하면 서버한테 특정 페이지좀 보여달라는 요청이다.

  근데 우리는 서버없고 그냥 리액트가 라우팅을 담당하고 있으므로, 존재않는 페이지 서버한테 요청해서 에러뜰 수 있다.

  안전빵으로 # 붙여준다. #뒤에 붙은것들은 서버로 요청안되니까! 

//index.js
import { BrowserRouter } from 'react-router-dom';


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

 

 

 


 

 

React Router 핵심 컴포넌트

 

 

Link

: <a>와 유사 기능 컴포넌트이다. <a>는 href로 경로를 지정하는 반면 <Link>sms to prop을 통해 경로를 지정한다.

 클릭하면 '도메인네임/지정경로'로 갱신된다.

<Link to='/ex'> ex </Link>

 

 

Route

 : 현재 주소창의 경로와 매치될 경우 보여줄 컴포넌트를 지정하는데 사용된다.

  path를 통해서 매치시킬 경로를 지정하고 component prop을 통해서 매치되었을 때 보여줄 컴포넌트를 할당한다.

<Route path="/ex" component={Ex} />

 

Router

 : <Link>와 <Route>가 함게 유기적으로 동작하도록 묶어주는데 사용한다.

   <Link>와 <Route>는 DOM트리 상에서 항상 <Router>를 공통상위 컴포넌트로 가져야한다.

<Router>
	<Link />
	<Route />
</Router>

 

 


 

 

Routing 예시

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


/* /datail이라고 적으면 /라는 경로도 포함되서 메인도 보여진다. exact붙여서 해결해준다. */
      <Route exact path="/">
        <div>메인페이지</div>
      </Route>
      <Route path="/detail">
        <div>상세페이지</div>
      </Route>
      
// 어쩌구 경로로 가면 card컴포넌트를 보여준다.(둘다 같은코드)
<Route path="/어쩌구" component={Card} ></Route>
<Route path="/어쩌구"> <Card/> </Route>

 

 

react-router는 각 페이지마다 다른 html을 보여주는게 아니라,

html을 싹 갈아엎어서 다른페이지처럼 보여지게 하는것이다.

 

 


 

 

Link, Switch,  useHistory 페이지 이동

 

 

> Link 태그는 새로고침없이 페이지를 바꿔준다.

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

function App() {
 return (
   <Link to="/">home</Link>
       ....

> NavLink

  현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일을 적용할 수 있다.

  링크가 활성화 되었을 때, activeStyle값을 props로 넣어주면 된다. (css class 적용시 activeClassName)

const activeStyle = {
 background : 'black',
 color: 'white'
}

return (
  ...
  <NavLink to="/경로" activeStyel={activeStyle} />
  ...
 )

 

 

> 이동함수 useHistory 함수 import해서 사용해서 뒤로가기버튼 만들어보자.

// 1. import하고 변수에 함수를 저장한다. 변수에 큰object{}자료가 저장된다.
import {useHistory} form 'react-router-dom';

function App() {
 let history= useHistory();
   ...
//history 저장된 자료중 goBack함수를 활용한다.

<button  onClick={() => {history.goBack();}} >
  뒤로가기
</button>

 

> 커스텀페이지로 이동하는 기능은 push()함수를 사용한다.

//push(/가고싶은경로)
<button  onClick={() => {history.push("/")}} >
  뒤로가기
</button>

 

 

 

 

> 매치되는 <Route> 전부 보여주지 말고 한번에 하나만 보고싶을 때 <Switch>를 쓴다.

/* /detail로 이동하면 <Detail>이랑  <div>hello</div> 두개 다 보여진다. */

function App(){
  return (
    <div>
      <Route exact path="/">
        메인
      </Route>
      <Route path="/detail">
        <Detail/>
      </Route>
      <Route path="/:id">
        <div>hello</div>
      </Route>
    </div>
  )
}
/* <Switch>로 감싸주면 Route가 여러개 매칭되어도 맨위의 Route하나만 보여준다. 
exact쓰지않고 해결가능하다. */

function App(){
  return (

      <Switch>
      
        <Route exact path="/">
          어쩌구
        </Route>
        <Route path="/detail">
          <Detail/>
        </Route>
        <Route path="/:id">
          <div>새로 만든 route입니다</div>
        </Route>
        
      </Switch>
      
  )
}

 

 

 


 

 

 

URL 파라미터 이용해서 여러 상세페이지 만들기

 

 

//App.js 파일에서 상세페이지 3개 만들고 싶어서 복사해서 만들어보았다.

function App(){
  return (
    <div>
      <나머지HTML/>
        <Route path="/detail/0">
          <Detail shoes={shoes}/>
        </Route>
        <Route path="/detail/1">
          <Detail shoes={shoes}/>
        </Route>
        <Route path="/detail/2">
          <Detail shoes={shoes}/>
        </Route>
    </div>

 

> 반복적인부분 반복문이아니라 URL 파라미터 문법으로 축약시켜준다.

   :id 자리에 아무 문자나 입력하면 <Detail>컴포넌트 보여준다.

   /detail/:id/:name 파라미터 몇개든 추가가능하다.

function App(){
  return (
    <div>
      <나머지HTML/>
        <Route path="/detail/:id">
          <Detail shoes={shoes}/>
        </Route>
    </div>
  )
}

 

 

> 각 URL 접속시 상품명을 다르게 보여주고 싶을 땐 useParams 을 사용한다.

 useParams()는 현재 url에 적힌 모든 파라미터를 {파라미터1, 파라미터2, ....} 로 저장해주는 함수이다.

 그것을 destructuring문법을 이용해서 따로 변수로 빼서 저장한 것이다.

 ( /detail/100 으로 접속하면 id라는 변수는 100이 되는 것이다.)

 

// useparams를 import로 가져오고 변수에 저장한다.

import { useHistory, useParams } from 'react-router-dom';

function Detail(props){

  let { id } = useParams();
  return (
         ...
          <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> 
          ...

 

 

 

> 데이터의 순서가 변경과 상관없이 페이지를 보여주고 싶다면?

  상품의 영구번호, 즉 id값으로 데이터를 불러오고 싶다면

  find(), filter() 등을 사용한다.

function Detail(props) {
   
  let { id } = useParams();
  //find는 array뒤에 붙이고, 콜백함수가 따라온다.
  let 찾은상품 = props.shoes.find((상품) => {      
  //콜백함수내의 파라미터는(상품) array안의 하나하나의 데이터를 의미한다.
    return 상품.id == id;
  //return 다음에는 조건식, 이게 참인 데이터만 새로운 변수에 저장한다.
  //현재 url의 /:id에 적힌갑소가 상품의 id가 같은지 비교하는 조건식이다.
  });

 

 

 

Nested Routing  상세

 

중첩라우팅이란 라우팅 맵핑을 최상위 컴포넌트뿐만 아니라 여러개의 컴포넌트에 걸쳐서 단계별로 정의하는 라우팅 기법이다.

 

Route props

중첩라우팅을 구현하려면 <Route> 컴포넌트의 componet prop으로 넘어온 컴포넌트에 prop으로 어떤 값들이 넘어오는지 대해 알아야한다.

<Router>
  <Route path="/about" component={About} />
</Router>

 

react router는 match, lacation, history라는 3개의 prop을 <about>컴포넌트에 넘겨준다.

<About>컴포넌트에서는 이 3개의 prop을 읽어서 각 객체가 어떤 데이터를 담고있는지 렌더링해 볼 수 있다.

 

import React from "react";

function About({ match, location, history }) {
  return (
    <>
      <h1>About</h1>
      <pre>{JSON.stringify(match, null, 2)}</pre>
      <pre>{JSON.stringify(location, null, 2)}</pre>
      <pre>{JSON.stringify(history, null, 2)}</pre>
    </>
  );
}

export default About;

중첩 라우팅 구현에는 매칭정보를 담고있는 match props가 사용된다.

match.url은 <Link> 컴포넌트를 위해 사용되고,

match.path는 <Route> 컴포넌트를 위해 사용된다.

 

match.url은 실제로 매칭된 url 문자열 ( ex. /articles/1 )을 담고있고,

match.path은 매칭에 사용된 경로의 패턴 ( ex. /articles/:id )을 담고있다.

 

 

> 중첩라우팅 구현

/users  : 유저목록 페이지

/users/유저아이디 : 유저상세 페이지

 

 

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/users" component={Users} />
  <Route component={NotFound} />
</Switch>

 

 

/users경로에 컴포넌트 맵핑하고 컴포넌트 내부에서 /users의 하위 경로에 대한 라우팅을 해준다.

import React from "react";
import { Route } from "react-router-dom";
import UserList from "./UserList";
import UserDetail from "./UserDetail";

function Users({ match }) {
  return (
    <>
      <h1>Users</h1>
      <Route exact path={match.path} component={UserList} />
      <Route path={`${match.path}/:id`} component={UserDetail} />
    </>
  );
}

export default Users;

Users 컴포넌트를 작성한다.

Users 컴포넌트는 <Route>의 component prop인자로 넘어갔기 때문에 match, history, location 3개의 porps를  가지고 있다.

이 중 match.path값을 사용한다.

 

첫 번째 <Route>컴포넌트는 /users경로에 {userlist}를 mapping하고,

두 번째는 /users/:id경로에 {userdetail} 컴포넌트를 mapping한다.

 

첫 번째 exact는 /users경로를 정확히 매칭하기위해서 사용한다.

exact 없을경우 /users로 시작하는 모든 경로가 매칭되서 userdetail페이지 표시될때 userlist도 표시된다.

 

:id는 url파라미터 정의할 때 사용하는 react router의 문법이다.

해당 파라미터는 변수화되어 맵핑된 컴포넌트에서 match.params.id로 읽어올 수 있다.

 

 

 

 

 

예제)

하위 UserList component에서 Link 사용

import React from "react";
import { Link } from "react-router-dom";
import { users } from "./data.json";

function UserList({ match }) {
  return (
    <>
      <h2>User List</h2>
      <ul>
        {users.map(({ id, name }) => (
          <li key={id}>
            <Link to={`${match.url}/${id}`}>{name}</Link>
          </li>
        ))}
      </ul>
    </>
  );
}

export default UserList;

이동할경로는 match.url뒤에 각 유저의 id를 붙여서 <Link>컴포넌트의 to prop에 넘겨준다.

match.path 대신 match.url을 사용하는 이유는 링크를 걸 때 경로 문자열아닌 경로 패턴을 사용하면 url 파라미터가 포함될 수 있기 때문이다.

 

 

 

하위 UserDetail component에서 history prop 사용

import React from "react";
import { users } from "./data.json";

function UserDetail({ match, history }) {
  const user = users.find((user) => user.id === match.params.id);
  return (
    <>
      <h2>User Detail</h2>
      <dt>id</dt>
      <dd>{user.id}</dd>
      <dt>name</dt>
      <dd>{user.name}</dd>
      <button onClick={() => history.goBack()}>Back</button>
    </>
  );
}

export default UserDetail;

match.params를 통해 경로에 포함되어있는 url 파라미터를 읽어 온다.

( users/1일 경우, match.params에 {id: "1"}이 할당되어서 match.params.id값은 1이되며,

이 값으로 유저를 조회하여 상세정보를 렌더링한다.

 

유저 목록페이지로 돌아가는 버튼에는 history prop의 goback()함수를 사용한다.

history는 브라우저의 이력정보와 관련 유틸리티 함수를 가지고있다.

 

 

 


 

 

404페이지

 

 

브라우저에 잘못된 경로가 입력되었을 때, 특정한 404페이지 보여줘야한다.

<Switch>로 모든 <Route> 컴포넌트를 묶어준다.

<Switch>를 사용하면 그 하위에 있는 <Route>컴포넌트 중에 매치되는 제일 첫번째 컴포넌트만 보여주고,

그 이후에 나오는 Route컴포넌트는 매치되더라도 무시된다.

 

 

path에 prop이 없는 <Route>컴포넌트 하나를 추가해주면, 이 <Route>는 모든경로에 매치가 가능해지고, 여기에 404를 할당해준다.

그러면 위에있는 Route중 매치된는 것이 없을경우 제일아래까지 내려오고,

이 마지막 <Route>컴포넌트가 매치되어 404페이지가 보여질 것이다.

 

<main>
  <Switch>
    <Route exact path="/" component={Home} />
    <Route path="/about" component={About} />
    <Route component={NotFound} />
  </Switch>
</main>

 

반응형

'• React' 카테고리의 다른 글

[React] useEffect / useReducer  (0) 2021.10.24
[React] styled-components / SASS / CSS Module  (0) 2021.10.24
[React] React hook basic  (0) 2021.10.21
[REACT] State / Event  (0) 2021.09.04
[REACT] Component / Props / Mock data  (0) 2021.09.01