상세 컨텐츠

본문 제목

<리액트를 다루는 기술> 13장: 리액트 라우터로 SPA 개발하기

21-22/21-22 리액트 스타터 -2

by dev otcroz 2022. 1. 24. 13:00

본문

728x90

INDEX

13장 리액트 라우터로 SPA 개발하기

1. SPA란?

1.1 SPA의 단점

2. 프로젝트 준비 및 기본적인 사용법

2.1 프로젝트 생성및 라이브러리 설치

2.2 프로젝트에 라우터 적용

2.3 페이지 만들기

2.4 Route 컴포넌트로 특정 주소에 컴포넌트 연결

2.5 Link 컴포넌트를 사용하여 다른 주소로 이동하기

 

3. Route 하나에 여러 개의 path 설정하기

3.1 App에서 todos 상태 사용하기

3.2 항목 추가 기능 구현하기

3.3 지우기 기능 구현하기

3.4 수정 기능

4. URL 파라미터와 쿼리

4.1 App에서 todos 상태 사용하기

4.2 항목 추가 기능 구현하기

5. 서브 라우트

6. 리액트 라우터 부가 기능

6.1 history

6.2 withRouter

6.3 Switch

6.4 NavLink

7. Question 개념 정리 및 코드 문제

● 개념 복습 문제

● 코드 문제

8. 참고 문헌


1. spa란?

SPA(Single Page Application) 한 개의 페이지로 이루어진 애플리케이션

전통적인 웹 페이지의 동작 구조

전통적인 웹 페이지에서의 동작

  • 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아옴
  • 페이지를 로딩할 때마다 서버에서 리소스를 전달받아 해석한 뒤 화면에 보여줌

➨ 사용자에게 보이는 화면을 "서버 측"에서 준비(사전에 html 파일을 만들어 제공, 템플릿 엔진 사용)

 

전통적인 웹 페이지에서의 문제점

성능상의 문제: 새로운 화면을 보여줘야 할 때마다 서버 측에서 모두 뷰(화면) 준비

트래픽이 많이 나옴, 사용자 몰림 현상으로 인한 서버 다운

사용자와 인터렉션이 자주 발생하는 모던 웹 애플리케이션에서 부적절함

#모던 웹: 현대적 웹을 뜻함 ex) 반응형 웹 

 

불필요한 로딩: 애플리케이션 내에서 화면 전환이 일어날 때마다 서버에 html 요청

사용자의 상태를 유지하는 것의 번거로움

바뀌지 않는 부분까지 새로 렌더링해야함

 

💡그럼 어떻게 보완해야할까?

리액트같은 라이브러리, 프레임워크 사용 ➨ 뷰의 렌더링을 "사용자의 브라우저"에서 담당

애플리케이션을 브라우저에서 불러옴/실행, 사용자와의 인터렉션 발생  필요한 부분 자바스크립트를 통해 업데이트

새로운 데이터가 필요한 경우 ➨ "서버 API"를 호출하여 필요한 데이터만 새로 불러옴

 

SPA(싱글 페이지 애플리케이션)의 동작 구조

SPA(싱글페이지)라고 해서 한 페이지인가요?

 "꼭 그렇지만은 않다."

서버에서 사용자에게 제공하는 페이지는 한 종류

해당 페이지에서 로딩된 자바스크립트, 현재 사용자 브라우저의 주소에 따라 다양한 화면을 보여주는 것이 가능

라우팅: 다른 주소에 다른 화면을 보여주는 기능

   ⊙ 리액트 라이브러리 자체에 라우팅 기능이 내장되어 있지 않다.

   ⊙ 브라우저의 API, 라이브러리를 사용하여 현재 사용자의 브라우저 주소에 따라 다양한 화면을 보여줌

 

리액트 라우팅 라이브러리: 리액트 라우터, 리치 라우터, Next.js 등등

  ※ 이 책에서는 리액트 라우터를 사용한다.  

       리액트 라우터는 클라이언트 사이드에서 이루어지는 라우팅을 간단하게 구현하도록 도와줌.

 

1.1 SPA의 단점

1. 앱의 규모가 커지면 자바스크립트 파일이 너무 커진다.

페이지 로딩 시 사용자가 실제 방문하지 않을 수도 있는 페이지의 스크립트도 불러온다.

 코드 스플리팅: 라우트별로 파일들을 나누어 트래픽, 로딩 속도 개선

 

2. 일반 크롤러에서 페이지의 정보를 제대로 수집하지 못할 수 있다.

브라우저에서 자바스크립트를 사용하여 라우팅을 관리

   ⊙ 자바스크립트를 실행하지 않은 일반 크롤러에서 페이지의 정보를 제대로 수집하지 못한다.

    구글, 네이버 등의 검색 엔진의 검색 결과에 페이지가 잘 나타나지 않을 수 있다.

 

3. 짧은 시간동안 흰 페이지가 나타날 수 있다.

자바스크립트가 실행될 때까지 페이지가 비어 있다.

 

➨ 2, 3번의 문제는 "서버 사이드 렌더링"을 통해 해결

#서버 사이드 렌더링: 서버에서 페이지를 그려 클라이언트에 보낸 후, 이를 화면에 표시

  💡전통적인 웹 페이지의 대부분은 서버 사이드 렌더링 방식을 사용한다.

         첫 렌더링 된 html을 클라이언트에게 전달하는 방식


2. 프로젝트 준비 및 기본적인 사용법

리액트 라우터로 SPA 개발하기

  • 프로젝트 생성 및 리액트 라우터 적용
  • 페이지 만들기
  • Route 컴포넌트로 특정 주소에 컴포넌트 연결
  • Link 컴포넌트로 라우트 이동
  • URL과 파라미터와 쿼리 이해하고 적용
  • 서브 라우트 적용

2.1 프로젝트 생성 및 라이브러리 설치

1. 리액트 프로젝트 생성 및 리액트 라이브러리 설치

$ yarn create react-app router-tutorial

$ cd router-tutorial

S yarn add react-router-dom

 

2.2 프로젝트에 라우터 적용

src/index.js 파일에서 react-router-dom에 내장되어 있는 "BrowserRouter 컴포넌트" 사용

BrowserRouter은 HTML5의 History API를 사용 

  • 새로고침하지 않고도 주소를 변경
  • 현재 주소에 관련된 정보 ➨  props로 쉽게 조회 및 사용

#History API: History 객체를 사용하여 브라우저의 세션 기록(현재 페이지를 불러온 탭, 프레임의 방문 기록)에 접근 및 조작하는 방법을 제공

//index.js
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);

 

2.3 페이지 만들기

라우트로 사용할 페이지 컴포넌트를 만들어보자. 

  • Home 컴포넌트: 사용자가 웹 사이트에 들어왔을 때 맨 처음 보여줄 페이지
  • About 컴포넌트: 웹 사이트 소개

1. Home.js

const Home = () => {
  return (
    <div>
      <h1>홈</h1>
      <p>홈, 그 페이지는 가장 먼저 보여지는 페이지,</p>
    </div>
  );
};

export default Home;

2. About.js

const About = () => {
  return (
    <div>
      <h1>소개</h1>
      <p>이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트입니다.</p>
    </div>
  );
};

export default About;

 

2.4 Route 컴포넌트로 특정 주소에 컴포넌트 연결

Route 컴포넌트: 사용자의 현재 경로에 따라 다른 컴포넌트를 보여주는 역할

Route 컴포넌트를 사용하여 어떤 주소 규칙을 가진 경로에서 어떤 컴포넌트를 보여줄 지 정의

 

React-router-dom v6이 업그레이드 되면서 변경된 사항들

1. 기존의 Route 컴포넌트 사용방식

//app.js
<div>
  <Route path="주소 규칙" component={보여 줄 컴포넌트} />
</div>

2. 변경된 Route 컴포넌트 사용 방식

기존과 다르게, Routes 컴포넌트로 Route를 감싼다.

보여 줄 컴포넌트를 정의할 때 component props가 아닌 element props를 사용한다.

//app.js   
<Routes>
  <Route path="주소규칙" element={<보여 줄 컴포넌트 이름 />} />
</Routes>

 

App.js에서 Route 컴포넌트를 사용하여 Home 컴포넌트와 App 컴포넌트를 보여주도록 설정해보자.

이때, Route 컴포넌트들을 Routes 컴포넌트로 감싸주어 사용한다.

//App.js
import { Route, Routes } from "react-router-dom";
import About from "./About";
import Home from "./Home";

const App = () => {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
  );
};

export default App;

App 컴포넌트 실행 화면

다음으로, 주소창에 localhost:3000/about 경로를 입력하여 들어간다.

그럼 about 컴포넌트가 보인다.

About 컴포넌트로 이동(로컬 주소/about) 후 실행화면

이상하다.. <리액트를 다루는 기술> 에서는 두 개의 컴포넌트가 뜬다고 되어있는데.. 

위에서도 소개했듯이 React-router-dom v6 업데이트에 의해서 이 부분이 수정되었다.

원래는 Route 컴포넌트의 props exact로, exact={true}를 사용하여 두 컴포넌트가 한 페이지에 나타나지 않도록 구현했지만,

이번 업데이트로 인해 한 페이지에 한 컴포넌트가 뜨도록 업데이트되었다.

이는 Routes를 사용했기 때문인데.. ☞Routes에 대해서 알고 싶다면 클릭!

즉, exact props가 사라지고 이 역할을 Routes 컴포넌트가 한다.

 

1. 기존의 코드 작성 방식

import { Route, Routes } from "react-router-dom";
import About from "./About";
import Home from "./Home";

const App = () => {
  return (
    <div>
      <Route path="/" component={Home} />
      <Route path="/about" component={About} />
    </div>
  );
};

export default App;

 

2. 업데이트 후 코드 작성 방식 : 위의 App.js 코드 참고

 

2.5 Link 컴포넌트를 사용하여 다른 주소로 이동하기

Link 컴포넌트: 클릭하면 다른 주소로 이동시켜주는 컴포넌트

Link 컴포넌트 ≒ <a> 태그의 역할

리액트 라우터를 사용할 때는 <a>태그를 사용할 수 없다. 이 태그는 페이지를 전환하는 과정에 페이지를 새로 불러오기 때문에 애플리케이션이 들고 있던 상태들을 모두 날려버린다. 즉, 렌더링된 컴포넌트들이 모두 사라지고 다시 처음부터 렌더링한다.

 

Link 컴포넌트를 사용하여 페이지 전환

  • 페이지를 새로 불러오지 않고 애플리케이션을 그대로 유지
  • HTML5 History API 사용  페이지의 주소 변경

Link 컴포넌트 자체는 <a>태그로 이루어져 있지만 페이지 전환을 방지하는 기능이 내장되어 있다.

<Link to="주소">내용</Link>

이제 App 컴포넌트에서 Link 컴포넌트를 적용해보자.

//app.js
import { Route, Routes, Link } from "react-router-dom";
import About from "./About";
import Home from "./Home";

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to="/">홈</Link>
        </li>
        <li>
          <Link to="/about">소개</Link>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </div>
  );
};

export default App;

 

결과 화면


3. Route 하나에 여러 개의 path 설정하기

Route 하나에 여러 개의 path를 지정  path props를 배열로 설정하여 각 주소들을 배열로 묶어줌

 

1. 기존: 여러 개의 path로 같은 컴포넌트를 보여줄 때

      <Routes>
        <Route path="/info" element={<Home />} />
        <Route path="/about" element={<Home />} />
      </Routes>

2. 업데이트 후

      <Routes>
        <Route path={['/info', '/about']} element={<Home />} />
      </Routes>

4. URL 파라미터와 쿼리

유동적인 값을 전달해야 할 때 파라미터 쿼리를 사용하여 값을 전달할 수 있다.

  • 파라미터 예시: /profile/velopert 
  • 쿼리 예시: /about?details=true

파라미터는 특정 아아디나 이름을 사용하여 조회할 때 사용

쿼리는 사용자가 키워드를 검색하거나 필요한 옵션을 전달할 때 사용


4.1 URL 파라미터

Profile 페이지에서 파라미터를 사용해보자. 

/profile/velopert 같은 형식으로 뒷부분에 유동적인 username 값을 넣어 줄 때 해당 값을 props로 받아와서 조회

//profile.js
const data = {
  velopert: {
    name: "김민준",
    description: "리액트를 좋아하는 개발자",
  },
  gildong: {
    name: "홍길동",
    description: "고전 소설 홍길동전의 주인공",
  },
};

const Profile = ({ match }) => {
  const { username } = match.params;
  const profile = data[username];

  if (!profile) {
    return <div>존재하지 않는 사용자입니다.</div>;
  }

  return (
    <div>
      <h3>
        {username}({profile.name})
      </h3>
      <p>{profile.description}</p>
    </div>
  );
};

export default Profile;

 

이상하다.. 오류가 발생하는데요?

1. 이전 버전의 파라미터 사용 방법

라우트로 사용되는 컴포넌트에서 받아오는 match 객체 안의 params 값을 참조

match 객체: 현재 컴포넌트가 어떤 경로 규칙에 의해 보이는지에 대한 정보

const { username } = match.params; 

 

2. 업데이트 후 파라미터 사용 방법

react-router-dom에서 useParams()를 import한다.

const { username } = useParams(); 로 수정한다.

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

const Profile = ({ match }) => {
  const { username } = useParams(); //useParams 사용
  const profile = data[username];
...

 

App.js에서는 path 값으로 "/profile/:username"이라고 넣어준다.

이렇게 하면, match.params.username 값을 통해 username을 조회할 수 있다.

import { Route, Routes, Link } from "react-router-dom";
import About from "./About";
import Home from "./Home";
import Profile from "./Profile";

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to="/">홈</Link>
        </li>
        <li>
          <Link to="/about">소개</Link>
        </li>
        <li>
          <Link to="/profile/velopert">velopert 프로필</Link>
        </li>
        <li>
          <Link to="/profile/gildong">gildong 프로필</Link>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/profile/:username" element={<Profile />} />
      </Routes>
    </div>
  );
};

export default App;

Profile 컴포넌트 적용 후 실행 화면

4.2 URL 쿼리

이번에는 about 페이지에서 쿼리를 받아온다.

react-router-dom이 업데이트 하면서 쿼리를 받아오는 방법도 달라졌다.

 

1. 이전 버전의 쿼리 사용 방법

location 객체에 들어있는 search 값에서 조회할 수 있었다.

{
  "pathname" : "/about",
  "search" : "?detail=true",
  "hash": ""
}

이 객체는 라우트로 사용된 컴포넌트에게 props로 전달되며 웹 애플리케이션의 현재 주소에 대한 정보를 지닌다.

쿼리 문자열을 객체로 변환할 때 qs라는 라이브러리를 사용한다.

$ yarn add qs

 

더보기

 

//About.js
import qs from 'qs'

const About = ({ location }) => {
	const query = qs.parse(location.search, {
		ignoreQueryPrefix: true   //쿼리 접두사 무시
	}

	const detail = query.detail === 'true'; // 쿼리의 파싱 결과값은 문자열

	return (
		<div>
			{detail && <p>해당 경로로 들어오면 보이는 텍스트입니다</p>}
		</div>
	)
}

 

2. 업데이트 후 쿼리 사용 방법

react-router-dom에서 useLocation을 import한다.

useLocation( )을 통해 search 값을 받아온 후,

search가 "?detail=true" 인지 확인하는 코드이다.

import { useLocation } from "react-reuter-dom"; // import

const About = () => {
  const { search } = useLocation();

  //현재 지금 경로가(search) '?detail=true' 인지 확인
  const showDetail = search === "?detail=true";

  return (
    <div>
      <h1>소개</h1>
      <p>이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트입니다.</p>
      {showDetail && <p>detail 값을 true로 설정하셨군요!</p>}
    </div>
  );
};

export default About;

 

이제 About 컴포넌트에서 location.search 값에 있는 detail이 true인지 아닌지에 따라 추가 정보를 보이도록 구현한다.

About 컴포넌트 적용 후 실행 화면

 

 


5. 서브 라우트

서브라우트: 라우트 내부에 또 라우트를 정의

라우트로 사용되고 있는 컴포넌트 내부에 또 Route 컴포넌트를 사용하면 된다.

 

react-router-dom 업데이트 전의 사용법(교재 340p 참고)

  • 컴포넌트에 render라는 props를 넣어주었다.
  • exact를 사용하였다.
더보기
//Profiles.js
import { Link, Route } from "react-router-dom";
import Profile from "./Profile";

const Profiles = () => {
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <Link to="/profiles/velopert">velopert</Link>
        </li>
        <li>
          <Link to="/profiles/gildong">gildong</Link>
        </li>
      </ul>
      <div>
        <Route path="/profiles" render={() => <div>사용자를 선택해주세요.</div>} />
        <Route path="/profiles/:username" component={Profile} />
      </div>
    </div>
  );
};

export default Profiles;

 

업데이트 후 사용 방법

 

v6 버전으로 업데이트되면서 render과 exact는 사라지고 element props로 대체되었다. 

  • render props    element props
  • exact   하위 페이지가 있다면 부모 라우터에 /* 추가 
  • 부모 경로까지 적을 필요 없이 파라미터만 적는다.
  • Routes로 감싸준다.

 

1. Profiles 컴포넌트 만들기

//Profiles.js
import { Link, Route, Routes } from "react-router-dom";
import Profile from "./Profile";

const Profiles = () => {
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <Link to="/profiles/velopert">velopert</Link>
        </li>
        <li>
          <Link to="/profiles/gildong">gildong</Link>
        </li>
      </ul>
      <Routes>
        <Route path="/*" element={<div>사용자를 선택해주세요.</div>} />
        <Route path=":username" element={<Profile />} />
      </Routes>
    </div>
  );
};

export default Profiles;

 

2. App 컴포넌트에 Profiles 컴포넌트 연결

import { Route, Routes, Link } from "react-router-dom";
import About from "./About";
import Home from "./Home";
import Profiles from "./Profiles"; //컴포넌트 import

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to="/">홈</Link>
        </li>
        <li>
          <Link to="/about">소개</Link>
        </li>
        <li>
          <Link to="/profiles">프로필</Link>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path={"/about"} element={<About />} />
        <Route path="/profiles/*" element={<Profiles />} /> 
      </Routes>
    </div>
  );
};

export default App;

6. 리액트 라우터 부가 기능

⚙️업데이트 전: 리액트 라우터의 부가기능은 크게 4가지가 있다. 

  • history
  • withRouter
  • Switch
  • NavLink

하지만, react-route-dom v6 버전으로 업데이트하면서 달라진 점이 있다면,

  • history  useNavigate
  • withRouter  사라짐
  • Switch  Routes로 변경
  • NavLink ➨ activeStyle, activeClassName 사라짐

6.1 history

history 객체는 라우트로 사용된 컴포넌트 match, location과 함께 전달되는 props이다.

이 객체를 통해 컴포넌트 내에 구현하는 메서드에서 라우터 API 호출 가능

특정 버튼을 눌렀을 때 뒤로 가는 동작, 로그인 후 화면 전환, 다른 페이지 이탈 방지 

 

1. 업데이트 전(v5) 코드 작성법

//HistorySample.js
import {Component} from 'react';

class HistorySample extends Component{
    //뒤로 가기
    handGoBack =() =>{
        this.props.history.goBack();
    };

    //홈으로 이동
    handGoHome = () =>{
        this.props.history.push('/');
    }

    //페이지를 빠져나갈 것인지 물어봄
    componentDidMount(){
        this.unblock = this.props.history.block('정말 떠나실 건가요?');
    }

    //컴포넌트가 언마운트되면 질문을 멈춤
    componentWillUnmount(){
        if(this.unblock){
            this.unblock();
        }
    }


    render(){
        return(
        <div>
            <button onClick={this.handGoBack}>뒤로</button>
            <button onClick={this.handGoHome}>홈으로</button>
        </div>
        );
    }

};

 

2. 업데이트 후(v6) 코드 작성법

useNavigate()를 사용하여 관리한다.

기존에는 history.block를 사용하여 블럭을 구현할 수 있었지만,

useNavigate()를 사용할 때 블럭 구현은 코드를 직접 작성하여 구현해야 한다.

 useNavigate()를 사용하여 블럭 창 띄우는 코드 작성

//HistorySample.js
import { useNavigate } from "react";

function NavigateSample() {
  const navigate = useNavigate();

  // 뒤로가기
  // 인덱스로 처리, 두번 뒤로 가고싶으면 -2
  const handGoBack = () => {
    navigate(-1);
  };

  // 홈으로 가기
  const handGoHome = () => {
    navigate("/");
  };

  //블럭 구현: 사이트 참고

  return (
    <div>
      <button onClick={handGoBack}>뒤로</button>
      <button onClick={handGoHome}>홈으로</button>
    </div>
  );
}

export default NavigateSample;

그리고 App.js에서 이 컴포넌트를 보이도록 설정한다.

//App.js
const App = () => {
  return (
    <div>
		(...)
          <Link to="/profiles">프로필</Link>
        </li>
        <li>
          <Link to="/history">history 예제</Link>
        </li>
      </ul>
      <Routes>
		(...)
        <Route path="/history" element={<HistorySample />} />
        <Route path="/*" element={<h1>존재하지 않는 페이지입니다.</h1>} />
      </Routes>
    </div>
  );
};

HistorySample 적용 실행 화면

 

6.2 withRouter

WithRouter HoC(Higher-order-component) 라우트로

사용된 컴포넌트가 아니어도 match, location, history 객체 접근할 수 있다.

#HoC: 고차 컴포넌트라고도 하며, 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환한다.

 

1. 업데이트 전(v5) 코드 작성법

WithRouter로 컴포넌트를 감싸주어 export 한다.

//WithRouterSample.js
import { WithRouter } from "react-router-dom";

const WithRouterSample = ({ location, match, history }) => {
  return (
    <div>
      <h4>location</h4>
      <textarea
        value={JSON.stringify(location, null, 2)}
        rows={7}
        readOnly={true}
      />
      <h4>match</h4>
      <textarea
        value={JSON.stringify(location, null, 2)}
        rows={7}
        readOnly={true}
      />
      <button onClick={() => history.push("/")}>홈으로</button>
    </div>
  );
};

export default withRouter(WithRouterSample); //withRouter로 컴포넌트를 감싸줌

 

2. 업데이트 후(v6) 코드 작성법

업데이트 후, withRouter이 사라졌다.

useParams, useLocation, useNavigate를 사용하여 코드를 작성한다.

//WithRouterSample.js
import { useParams, useLocation, useNavigate } from "react-router-dom";

const WithRouterSample = () => {
  const params = useParams();
  const location = useLocation();
  const navigate = useNavigate();

  return (
    <div>
      <h4>location</h4>
      <textarea
        value={JSON.stringify(location, null, 2)}
        rows={7}
        readOnly={true}
      />
      <h4>match</h4>
      <textarea value={JSON.stringify(params)} rows={7} readOnly={true} />
      <button onClick={() => navigate("/")}>홈으로</button>
    </div>
  );
};

export default WithRouterSample;

 

그리고 Profiles.js에서 이 컴포넌트를 렌더링해준다.

//profiles.js
import withRouterSample from './withRouterSample';

<div> 
  (...)
  <WithRouterSample/>
</div>

export default Profiles;

WithRouter 컴포넌트 적용 후 실행 화면

6.3 Switch

여러 Route를 감싸서 그 중 일치하는 단 하나의 라우트만을 렌더링시켜준다.

이때, v6 버전 업데이트에 의해 Switch는 Routes로 작성하여 사용한다. 

❗그래서 Routes로 여러 개의 Route로 감쌌을 때, 경로가 겹치지 않으면서 주소 규칙에 일치하는 하나의 Route를 웹 페이지에 보여줬던 것이다.

 

1. 업데이트 전(v5) 코드 작성법

//App.js
  <Switch>
    <Route path="/" element={<Home />} />
    <Route path={"/about"} element={<About />} />
    <Route path="/profiles/*" element={<Profiles />} />
    <Route path="/*" element={<h1>존재하지 않는 페이지입니다.</h1>} />
  </Switch>

2. 업데이트 후(v6) 코드 작성법

//App.js
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path={"/about"} element={<About />} />
    <Route path="/profiles/*" element={<Profiles />} />
    <Route path="/*" element={<h1>존재하지 않는 페이지입니다.</h1>} />
  </Routes>

Routes 컴포넌트 적용 후 실행 화면

 

6.4 NavLink

NavLink는 Link와 비슷한 역할

현재 경로와 Link에서 사용하는 경로가 일지하는 경우 특정 스타일 혹은 CSS 클래스를 적용하는 컴포넌트 

 

1. 업데이트 전(v5) 코드 작성법

  • activeStyle: 링크가 활성화되었을 때 스타일 적용
  • activeClassName: CSS 클래스 적용
// profiles.js
import { NavLink, Route, Routes } from "react-router-dom";
import Profile from "./Profile";

const Profiles = () => {
  const activeStyle = {
    background: "black",
    color: "white",
  };

  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <NavLink activeStyle={activeStyle} to="/profiles/velopert">
            velopert
          </NavLink>
        </li>
        <li>
          <NavLink activeStyle={activeStyle} to="/profiles/gildong">
            gildong
          </NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/*" element={<div>사용자를 선택해주세요.</div>} />
        <Route path=":username" element={<Profile />} />
      </Routes>
    </div>
  );
};

export default Profiles;

 

2. 업데이트 후(v6) 코드 작성법

activeStyle activeClassName이 사라졌다.

기존에 있는 style className을 사용하여 적용하는 방식

//Profiles.js
import { NavLink, Route, Routes } from "react-router-dom";
import Profile from "./Profile";

const Profiles = () => {
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <NavLink
            style={({ isActive }) => ({
              background: isActive ? "black" : "white",
            })}
            to="/profiles/velopert"
          >
            velopert
          </NavLink>
        </li>
        <li>
          <NavLink
            style={({ isActive }) => ({
              background: isActive ? "black" : "white",
            })}
            to="/profiles/gildong"
          >
            gildong
          </NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/*" element={<div>사용자를 선택해주세요.</div>} />
        <Route path=":username" element={<Profile />} />
      </Routes>
    </div>
  );
};

export default Profiles;

NavLink 컴포넌트 적용 후 실행 화면

 

 


7. Question 개념 및 코드 문제

 

 개념 복습 문제

1. 한 개의 페이지로 이루어진 애플리케이션은 (SPA)(이)라고 하며, 사용자의 ( 브라우저 주소 )에 따라 한 페이지에서 다양한 화면을  보여주는 것이 가능하다.

2. 전통적인 웹 페이지에서의 문제점은 새로운 화면을 보여줘야 할 때마다 ( 서버 ) 측에서 모두 뷰를 준비해야하고, 화면 전환이 일어날 때마다 (서버)에 html을 요청해야하는 단점이 있다. 이를 해결하기 위해 뷰의 렌더링을 (사용자의 브라우저)에서 담당하는 방법이 있다.

3. 전통적인 웹페이지의 렌더링 방식은 (서버 사이드 렌더링)이다.

 

4. 맨 처음 프로젝트에 라우터를 적용하기 위해 (src/index.js) 파일에서 react-router-dom에 내장되어 있는 (BrowserRouter) 컴포넌트를 사용한다. 이 컴포넌트는 (History) API를 사용한다. 

5. 라우터를 적용하면 새로고침하지 않고도 (주소)을/를 변경할 수 있고, 현재 주소에 관련된 정보를 (props)(으)로 쉽게 조회 및 사용이 가능하다.

6. 어떤 주소 규칙을 가진 경로에서 어떤 컴포넌트를 보여줄 지 정의하기 위해 (Route) 컴포넌트를 사용한다. 최근에 react-router-dom의 업데이트(v6)로 인해 이 컴포넌트를 사용하기 위해 (Routes) 컴포넌트로 감싸줘야 한다.

7. 클릭하면 다른 주소로 이동시켜주는 (Link) 컴포넌트가 있다. 이 컴포넌트는 (<a>태그)(으)로 이루어져있지만 (페이지 전환)을/를 방지하는 기능이 있다.

 

8. 유동적인 값을 전달받을 때 (파라미터)와/과 (쿼리)를 통해 값을 전달받을 수 있다.

9. 업데이트에 의해 파라미터는 (useParams()) 메서드를 통해 값을 전달받고, 쿼리는 (useLocation())을 통해 값을 전달받는다.

10. (서브라우트)은/는 라우트 내부에 또 다른 라우터를 정의한 것이다. 이를 구현하기 위해 라우터 안에 (Route)컴포넌트를 사용하면 된다.

 

11. (withRouter)은 사용된 컴포넌트가 아니어도 match, location, history 객체에 접근할 수 있다. 하지만 최근 업데이트로 인해 이 메서드는 사라졌고, (useParams), (useLocation), (useNavigate) 메서드를 사용하여 코드를 작성한다.

12. 여러 Route를 감싸서 그 중 일치하는 단 하나의 라우트만을 렌더링시켜주는 컴포넌트를 (Switch)라고 한다. 이때, v6 버전 업데이트에 의해 (Routes) 컴포넌트로 대체되었다.

13. Link와 비슷한 역할을 가지며,  현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 CSS 클래스를 적용하는 컴포넌트를 (NavLink) 컴포넌트가 담당한다.

 

 코드 문제

1. 프로젝트에 라우터를 적용하기 위해 index.js 작성하기

//index.js
import ReactDOM from "react-dom";
//import 필요
import "./index.css";
import App from "./App";

ReactDOM.render(
	//작성
  document.getElementById("root")
);

2.

(1) About와 Home 컴포넌트를 렌더링하는 코드 작성하기

(2) v6 버전으로 About 컴포넌트와 Home 컴포넌트를 렌더링하는 코드 작성하기

//App.js
import { Route, Routes } from "react-router-dom";
import About from "./About";
import Home from "./Home";

const App = () => {
  return (
	//여기를 작성하세요
  );
};

export default App;

3. 2번에서 작성한 컴포넌트에서 Link 컴포넌트를 적용하여 아래의 결과처럼 나오도록 코드 작성하기

실행 화면


8. 참고 문헌

 react Router 공식 문서

 리액트 라우터가 업그레이드 되면서 달라진 것

리액트 라우터 v6: 업데이트 후 달라진 점 : <리액트를 다루는 기술> 교재와 비교하여 달라진 점을 항목별로 확인할 수 있음


Corner React Starter #2

Editor 유숨숨

728x90

관련글 더보기