JS/React

리액트 라우터

0304호 2023. 1. 19.

SPA란? (single page application)

하나의 페이지로 만들어진 어플리케이션을 의미한다.

 

SPA는 html파일을 브라우저 측에서 로드하고, 필요한 데이터는 API와 ajax통신을 이용해서 처리합니다.

브라우저에서 사용자가 상호작용 하면 필요한 부분만 업데이트 해서 처리합니다.

멀티플랫폼 Android, IOS에 대응하여 웹뷰로 처리하는 목적으로도 사용됩니다.

 

SPA의 단점

  • 앱의 규모가 커지면, JS파일도 너무 커져서 로딩이 오래걸리게 됩니다.
  • 브라우저에서 렌더링이 완료되기 까지 비어있는 화면이 나오게 됩니다.
  • 그래서 규모가 큰 어플리케이션은 SSR(서버사이드 렌더링) 방식으로 처리합니다. (웹팩 설정 필요)
  • 클라이언트에서 거의 처리하므로  CSR(Client-Side Rendering) 렌더링 방식

 

라우팅이란?

  • 브라우저의 주소상태에 따라 다양한 화면을 보여주도록 처리하는 것을 라우팅이라고 합니다.
  • 여러페이지로 구성된 웹 어플리케이션을 만들 때 페이지별로 컴포넌트를 분리해가면서 프로젝트를 관리하기 위해 필요한 것, 라우팅시스템
  • 프레임워크에는 리액트 라우터와 Next.js가 있다. 

+) Next.js란?

서버사이드렌더링, 정적 웹페이지 생성 등 리액트 기반 웹 어플리케이션 기능들을 가능하게 하는 프레임워크이다.

 

사용이유

  • create-react-app로 프로젝트를 생성하게 되면 기본적으로  SPA에 CSR(클라이언트 렌더링) 입니다.
  • 하나의 페이지만 사용하게 되는 것입니다.
  • SPA이지만 라우터를 활용해서 사용자로 하여금 여러 페이지가 존재하는 것처럼 느껴지게 할 수 있습니다.

 

라우터 설치하고 프로젝트 시작하기

라우터는 리액터에서 제공해주는 하나의 모듈이다, 명령문으로 설치가 가능하다. 아래의 명령문을 확인하자.

기존에 생성된 프로젝트에 들어있다면 ..cd명령문을 이용해서 나가준다. 그 다음에 라우터 생성문을 입력해주면된다.

 

1. 라우터를 적용할 프로젝트 생성

npm create react-app 프로젝트명

2. 라우터 설치

npm add 모듈명-dom

생성한 파일을 open folder하고 라우터를 설치한다.

3. 프로젝트 시작

npm start

라우터 적용하기

  •  라우터를 사용할때는 index.js에서 App컴포넌트를 <BrowserRouter>로 감싸줍니다.
더보기
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom'; //라우터 안에 들어있는 기능이므로 자동으로 임포트해준다.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <BrowserRouter>
    <App />
    </BrowserRouter>

);

// 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();
  •  페이지 컴포넌트 만들기
  •  App컴포넌트에서 <Routes>를 사용해서 분기하기
  • path를 지정해서 url경로를 지정해주고, element를 통해 컴포넌트를 연결해줍니다.
더보기
import logo from './logo.svg';
import './App.css';
import Home from './component/Home';
import { Route, Routes } from 'react-router-dom';
import User from './component/User';
import Info from './component/Info';

function App() {
  /*
  1. index.js에서 브라우저 라우터로 app을 감싸준다.

  2. 각각의 컴포넌트를 만든다.

   */

  return (
    <Routes>
      <Route path='/' element={<Home />}/>
      <Route path='/user' element={<User/>}/>
      <Route path='/info' element={<Info/>}/>
    </Routes>
  );
}

export default App;
  •  주소요청을 통해 확인하기

각각의 설정한 경로를 통해 url에 접속할 수 있다.


Link를 이용해서 다른페이지로 이동하기

  • link태그는 화면에서 a태그로 생성됩니다.
  • to 속성에는 연결할 요청주소를 적습니다 (라우터주소).
  • 어느 컴포넌트든 사용할 수 있습니다
import { Link } from "react-router-dom";


const Home = () => {
    return (
        <>
            <div>
                <h3>Home페이지..</h3>
                <ul>
                    <li><Link to="/user">회원페이지</Link></li>
                    <li><Link to="/info">회원정보페이지</Link></li>
                </ul>
            </div>
        </>
    )
}

export default Home;
 
 <Link></Link>로 묶으면 자동으로  a태그가 생성이 됩니다.

URL파라미터 or 쿼리스트링

  • 쿼리스트링은 주소의 ? 뒤에 키=값 의 형태로 넘어가는 매개값입니다.
  • 별도의 라우터 설정은 하지 않아도 됩니다.
  • 컴포넌트에서는 useLocation() 훅 or useSearchParams() 훅을 사용 해서 쿼리스트링을 받을 수 있습니다.
/경로?키=값&키=값

쿼리스트링

 쿼리스트링 ? 키=값
  - useLocation()
  - useSearchParam()

1. 컴포넌트에서 사용하는 방법

 useLocation() 훅

const location = useLocation();  

useSearchParams() 훅 

  • 배열을 반환합니다.
  • 첫 번째 요소는 쿼리파라미터를 조회하거나 수정하는 get, set이 담긴 객체
  • 두 번째 요소는 쿼리파라미터를 객체로 업데이트 하는 함수 반환
const [객체, function] = useSearchParams() 

예시 >

더보기

App.js

.../
return (
    <Routes>
      <Route path='/user' element={<User/>}/>
    </Routes>
  );

User.js

import { useState } from "react";
import { useLocation, useSearchParams } from "react-router-dom";


const User = () => {
    //쿼리스트링으로 넘어오는 값을 받기
    //1. useLocation Hook
    // const location = useLocation();
    // console.log(location); //객체 안에 쿼리스트링 값은 분해해서 사용

    //2. useSearchParams Hook
    //배열반환 [값을 조회하거나 수정하는 get,set,쿼리스트링을 업데이트하는 객체]
    const [obj, setObj] = useSearchParams();
    // console.log(obj); //URLSearchParams {}
    // console.log(setObj);

    //매개변수는 넘어오는 키값을 쓸 수 있다.
    let id = obj.get("id");
    let age = obj.get("age");
    console.log(id, age);


    return (
        <>
            <div>
                <h3>User페이지..</h3>

                쿼리스트링으로 넘어온 id : {id}<br />
                쿼리스트링으로 넘어온 age : {age}<br />
            </div>
        </>
    )
}

export default User;

 

setObj를 이용해서 강제로 쿼리스트링 값 변경하기

import { useState } from "react";
import { useLocation, useSearchParams } from "react-router-dom";


const User = () => {

    const [obj, setObj] = useSearchParams();

    let id = obj.get("id");
    let age = obj.get("age");

    const handleClick = () => {
        let num = parseInt(age) + 1;
        setObj({id:"변경", age:num})
    }

    return (
        <>
            <div>
                <h3>User페이지..</h3>

                쿼리스트링으로 넘어온 id : {id}<br />
                쿼리스트링으로 넘어온 age : {age}<br />

                <button onClick={handleClick}>쿼리스트링 강제수정</button>
            </div>
        </>
    )
}

export default User;

 

URL파라미터

URL파라미터
  - 라우터를 설정 /경로/:값
  - useParams() 값을 받습니다.
  • URL파라미터는 주소 뒤에 /경로/값/값 의 형태로 넘어가는 매개값입니다.
  • 라우터에 추가적인 설정이 필요합니다. ( /주소:키 ) 여러개일 경우에는 :으로 계속 연결해서 사용할 수 있다. :키:키...
  • 컴포넌트에서는 useParams() 훅을 사용하여 URL파라미터를 받을 수 있습니다.

1. 라우터에서 사용하는 방법

function App() {

  return (
    <Routes>
        .....
        <Route path='/info:num' element={<Info/>}/>
    </Routes>
  );
}

export default App;

2. 링크에서 사용하는 방법

//.....
return (
	<ul>
		<li><Link to='/info/1'>1번 info</Link></li>
		<li><Link to='/info/2'>2번 info</Link></li>
		<li><Link to='/info/3'>3번 info</Link></li>
	</ul>
)

3. 컴포넌트에서 사용하는 방법

useParams() 훅

 

/param에는 link로 넘어온 키가 담겨 있습니다.

let param = useParams();

예시 >

더보기

App.js

.../
return (
    <Routes>
      <Route path='/info/:num' element={<Info/>}/>
    </Routes>
  );

Info.js (컴포넌트)

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


const Info = () => {

    const data = {
        1: { name: "홍길동", subject: "리액트라우터" },
        2: { name: "이순신", subject: "리액트props" },
        3: { name: "박희진", subject: "리액트state" },
    }

    //useParams()
    let param = useParams();
    // console.log(param); // URL주소의 값을 키로 받아줍니다.
    // console.log(param.num);
    
    
    const {name, subject} = data[param.num];
    console.log(name,subject);

    return (
        <>
            <div>
                <h3>Info페이지..</h3>
                {name}님의 데이터 {subject}
            </div>
        </>
    )
}

export default Info;

 


중첩라우터로 공통 부분 처리하기

  • 글페이지가 있고, 글에 따른 상세화면이 있다고 가정해 봅시다.
  • 라우터의 설정은 아래 처럼 보여질 수 있습니다.
  • 아래 설정은 두 라우터가 다르기 때문에 각각 다른 화면이 보입니다.
{/* 각각 다른화면을 구현한 예시 */}
<Routes>
	<Route path='/board' element={<Board/>}/>
	<Route path='/board/:num' element={<BoardContent/>}/>
</Routes>
  • 만약 Board 목록 페이지를 공통으로 사용하고 상세페이지를 서브로 보여주도록 처리하려면 중첩라우터를 활용할 수 있습니다.
  • 중첩라우터로 적용되면 부모컴포넌트에서 <Outlet> 컴포넌트를 활용해서 하위 라우터를 보여지게 할 수 있습니다.

아래는 중첩라우터로 적용한 예시이다.

{/* 중첩라우터 - 공통부분처리 (Board에 가서 Outlet컴포넌트 표기) */}
<Routes>
	<Route path='/board' element={<Board/>}> //상위 부모라우터
		<Route path=':num' element={<BoardContent/>}/> //하위 자식 라우터
	</Route>
</Routes>

Board.js

const Board = () => {

    return (
        <div>
            <h3>게시글목록</h3>
            <ul>
                <li><Link to='/board/1' >글1</Link></li>
                <li><Link to='/board/2' >글2</Link></li>
                <li><Link to='/board/3' >글3</Link></li> 
             </ul>

            {/* Oulet컴포넌트가 사용된 자리에 중첩된 내용이 보여지게됩니다 */}
            <Outlet/>
        </div>
    )
}

export default Board;

BoardContent.js

const BoardContent = () => {

    let {num} = useParams()

    return (
        <div>
            <h3>글 상세페이지</h3>
            {num}번 글입니다      
        </div>
    )
}

export default BoardContent;

<Outlet/>컴포넌트를 활용해서 하위 컴포넌트를 보여지게 한 예시문제 >

더보기

App.js

import logo from './logo.svg';
import './App.css';
import Home from './component/Home';
import { Outlet, Route, Routes } from 'react-router-dom';
import User from './component/User';
import Info from './component/Info';
import BoardContent from './component/BoardContent';
import Board from './component/Board';
import Header from './component/layout/Header';

function App() {
  /*
  1. index.js에서 브라우저 라우터로 app을 감싸준다.

  2. 각각의 컴포넌트를 만든다.

  3. Route를 이용해서 주소별로 컴포넌트 연결합니다,


  Link컴포넌트
  - a태그를 대체합니다.
  - to속성에 "라우터주소" 적어서 이동하면 됩니다.

  쿼리스트링 ? 키=값
  - useLocation()
  - useSearchParam()

  URL파라미터
  -라우터를 설정 /경로:값
  -useParams() 값을 받습니다.

   */

  return (
    <Routes>
      {/* 중첩라우터 - 헤더부분처리 (Header에 가서 Outlet컴포넌트 표기) */}
      <Route element={<Header />}>
        <Route path='/' element={<Home />} />
        <Route path='/user' element={<User />} />
        <Route path='/info/:num' element={<Info />} />
      </Route>
      {/* 각각 다른화면을 구현한 예시 */}
      {/* <Route path='/board' element={<Board />} />
      <Route path='/board/:num' element={<BoardContent />} /> */}

      {/* 중첩라우터 - 공통부분처리 (Board에 가서 Outlet컴포넌트 표기) */}
      <Route path='/board' element={<Board />}>
        <Route path=':num' element={<BoardContent />} />
      </Route>

    </Routes>
  );
}

export default App;

Header.js

import { Outlet } from 'react-router-dom';
import styled from './Header.module.css';

const Header = () => {
    return (
        <>
            <header className={styled.wrap}>
                <h3>헤더파일</h3>
                <ul className={styled.wrap_list}>
                    <li>목록</li>
                    <li>목록</li>
                    <li>목록</li>
                </ul>

                <div>
                    <button>버튼</button>
                    <button>버튼</button>
                </div>
            </header>
            <section>
                {/* 헤더 하위의 라우터 표현 */}
                <Outlet/>
            </section>
        </>
    )
}

export default Header;

가장 상위에 위치한 컴포넌트 내부에 선언하면 상위컴포넌트에 하위 라우터가 표현이된다.

 

라우터의 부가적인 기능

1. NavLink 컴포넌트

  • 링크에서 사용하는 경로가 라우터의 경로와 일치하면 특정스타일을 적용 (활성화기능)
  • NavLink는 {isActive: boolean}을 함수의 매개변수로 사용할 수 있게 전달해줍니다.
  • 반드시 {isActive} 변수로 구조분해할당 해야합니다.
예시 >
const myStyle = {color: "red", backgroundColor: "yellow"


<li><NavLink to="/board/1" style={({isActive}) => isActive ? myStyle : undefined}>글1</NavLink></li>​

2. useNavigate() 훅 vs Navigate 컴포넌트 

 

useNavigate() 훅

  • JS의 history객체를 대신합니다.
  • 이벤트에서 사용

Navigate 컴포넌트 

  • 리다이렉트기능 
  • 렌더링시에 사용

- useNavigate() Hook

  • useNavigate훅 은 특정 event가 발생할 때,  url을 조작할 수 있는 함수를 제공합니다.
  • react v6 에서 useHistory 가 변화한 것입니다. (JS의 history객체를 대신 합니다)

사용법

let navigator = useNavigate();

예시 >

import { Fragment } from "react";
import { NavLink, Outlet, useNavigate } from "react-router-dom";

const Header = () => {
    //useNavigate() 훅
    let nav = useNavigate();

    const goHome = () => {
        nav('/내가원하는 주소') 
    }
    return (
    	<button onClick={goHome}>이동</button>
        
           <button onClick={() => nav(-1)}>
            Go back
          </button>
          <button onClick={() => nav(1)}>
            Go forward
          </button>
    )

}
export default Header;

- Navigate 컴포넌트

  • <Navigate> 컴포넌트는 렌더링 될 때 현재 위치를 변경합니다.
  • useNavigate()훅과 비슷해보이지만 useNavigate()훅은 렌더링 과정에 사용할 수 없습니다.

위쪽에 주석처리 된 부분은 useNavigate()훅을 사용했지만 렌더링 과정에서는 사용이 불가능해서,

navigate컴포넌트를 사용한 예시이다.

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


const MyPage = () => {
    //첫번째 렌더링 과정에서는 사용할 수 없음
    // let nav = useNavigate();
    // let loginYN = false; //로그인여부
    // if(loginYN === false){
    //     nav('/');
    // }


    // replace={true}를 설정하면 기록을 남기지않는다. (url접속 히스토리?)
    let loginYN = false; //로그인여부
    if(loginYN === false){
        return <Navigate to="/" replace={true} />
    }

    return (
            <div>
                권한있는 사람만 접근이가능
            </div>
    )
}

export default MyPage;

 

'JS > React' 카테고리의 다른 글

React Ajax  (0) 2023.01.20
React Hook Reducer  (0) 2023.01.18
React Hook Ref  (0) 2023.01.18
React Hook State & Effect  (0) 2023.01.18
React Iteration Components (컴포넌트 반복)  (0) 2023.01.17

댓글