React 회사에서 열공! #28

CoderS·2022년 1월 10일
0

리액트 Remind

목록 보기
28/32

#28 새로운 환경에 적응하기

react-router 를 이용한 리액트 싱글 페이지 애플리케이션 만들기

※ SPA 란?

Single Page Application (싱글 페이지 어플리케이션) 의 약자이다. 말 그대로, 1개인 어플리케이션이란 뜻을 의미한다. 전통적인 구조는, 여러 페이지로 구성되어있다.

유저가 요청 할 때마다 페이지가 새로고침되며, 페이지를 로딩 할 때 마다 서버로부터 리소스를 전달받아서 렌더링을 한다.

요즘은 웹에서 제공하는 정보가 정말로 많기 때문에 속도적인 측면에서 문제가 많고, 이를 해소하기 위해서 압축과 캐싱을 통해서 서비스를 제공되고 있다.

하지만 이는 사용자와 인터랙션이 많은 현대 웹 어플리케이션에서는 충분하지 않을 가능이 크다. 렌더링하는 것을 서버쪽에서 담당한다는 것은, 그 만큼 렌더링을 위해서 서버 자원이 사용되고있고, 불필요한 트래픽도 낭비되고 있다.

그리하여 우리는 리액트와 같은 라이브러리 혹은 프레임워크를 사용해서 뷰 렌더링을 유저의 브라우저가 담당하도록 하고, 어플리케이션을 브라우저에 로드 한 다음 필요한 데이터만 전달받아 보여주는 것이다.

싱글페이지라고 해서, 한 종류의 화면만 있는것은 아니다.

예 : 블로그를 만든다면 -> 홈, 포스트, 목록, 포스트, 글쓰기 등의 화면이 있겠다. 또한 화면에 따라 주소도 만들어줘야 한다. 주소가 있어야 사람들이 북마크도 할 수 있고 구글같은 서비스를 통해서 유입이 될 수 있기 때문이다.

다른 주소에 따라 다른 뷰를 보여주는 것을 라우팅이라고 하는데, 리액트에는 이 기능이 내장되어있지 않는다. 따라서 우리가 직접 브라우저의 API 를 사용하고 상태를 설정하여 다른 뷰를 보여줘야 한다.

이번에 알아보게 될 react-router 는 써드파티 라이브러리로서 공식은 아니지만 가장 많이 사용되고 있는 라이브러리이다. 이 라이브러리는 클라이언트 사이드에서 이뤄지는 라우팅을 간단하게 해준다. 또한 서버 사이드 렌더링도 도와주는 도구들도 존재한다. 그리고 이 라우터는 react-native 에서도 사용 될 수 있다.

SPA 단점

  • 앱의 규모가 커지면 자바스크립트 파일 사이즈가 너무 커진다는 것이다. 유저가 실제로 방문하지 않을수도 있는 페이지에 관련된 렌더링 관련 스크립트도 불러오기 때문이다.
  • 자바스크립트를 실행하지 않는 일반 크롤러에선 페이지의 정보를 제대로 받아가지 못한다는 점이다. 때문에 구글, 네이버, 다음 등 검색엔진에서 페이지가 검색결과에서 잘 안나타날 수 있다.
  • 또한, 자바스크립트가 실행되는 동안 페이지가 비어있기 때문에, 사용자는 짧은 시간동안 흰 페이지가 나타날 수도 있다는 단점도 존재한다.

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

우선, 리액트 라우터를 사용할 프로젝트를 준비해준다.

$ npx create-react-app router-tutorial

다음으로 해당 프로젝트 디렉토리 루트로 이동해서 라우터 관련 라이브러리를 설치해준다.

$ cd router-tutorial
$ npm install react-router-dom

※ 프로젝트에 라우터 적용

라우터 적용은 index.js 에서 BrowserRouter 라는 컴포넌트를 사용해서 구현하면 된다.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'; // * BrowserRouter 불러오기
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

// * App 을 BrowserRouter 로 감싸기
ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

serviceWorker.unregister();

※ 페이지 만들기

그럼 이제 라우터로 사용 할 페이지 컴포넌트를 만들 차례이다.

유저가

  • 웹 사이트에 처음 들어왔을 때 보여줄 Home 컴포넌트와
  • 웹 사이트의 소개를 보여주는 About 컴포넌트를 만들어보겠다.

src 에 Home.js 와 About.js 를 만들어주고 밑에 있는 코드를 참고하면 된다.

Home.js

import React from 'react';

const Home = () => {
  return (
    <div>
      <h1></h1>
      <p>이곳은 홈이에요. 가장 먼저 보여지는 페이지죠.</p>
    </div>
  );
};

export default Home;

About.js

import React from 'react';

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

export default About;

페이지로 사용 할 모든 컴포넌트는 완성이되었다.

※ Route: 특정 주소에 컴포넌트 연결하기

우리는 사용자가 요청하는 주소에 따라 다른 컴포넌트를 보여주겠다. 이 때 이러한 작업을 할 때는 Route 라는 컴포넌트를 사용해준다.

사용 방식!

<Routes>
 <Route path="주소규칙" element={<보여주고싶은 컴포넌트 />}>
</Routes>

6버전으로 바뀌면서 Route 를 Routes 로 감싸주고 component 대신 element 지정해준다.

기존에 있던 App.js 코드들을 지워주고 Route 를 렌더링해준다.

App.js

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

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

export default App;

여기까지 완료했으면 npm start 으로 개발서버를 실행해준다.

URL 끝에다가 / 경로로 들어가면 홈 컴포넌트가 뜨고...

/about 경로로 들어가면, about 컴포넌트가 뜨게된다.

전 5버전은 exact 라는 props 를 true 로 설정해서 주로 Home 에 설정했는데 만약 exact 를 사용하지 않으면 밑에와 같은 결과를 초래한다.

출처 : 벨로퍼트와 함께하는 모던 리액트

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

우리는 리액트 라우터를 사용할땐 일반 a 태그를 사용하면 안된다. 만약에 사용할 것이면 onClick 에 e.preventDefault( ) 를 호출하고 따로 자바스크립트로 주소를 변환시켜주어야 하는 번거로움이 있다.

그 대신에 Link 라는 컴포넌트를 사용해야하는데, 그 이유는 a 태그의 기본적인 특성상 페이지를 이동시키면서, 아예 새로 불러오게하는 특징이 있다. 그렇게 되면서 우리 리액트 앱이 지니고있던 상태들도 초기화되고, 렌더링된 컴포넌트도 모두 사라져서 새롭게 렌더링을 하게된다.

그러하기 때문에 a 태그 대신에 Link 컴포넌트를 사용하는데 이 컴포넌트는 브라우저의 주소만 바꿀뿐 페이지를 새로 불러오지는 않는다.

App.js 파일로 가서 Link 컴포넌트를 추가해준다.

App.js

import React from 'react';
import { Route, Link, Routes } 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>
      <hr />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </div>
  );
};

export default App;

Home 화면

About 화면

파라미터와 쿼리

우리는 페이지 주소를 정의할 때, 유동적인 값을 전달해야 할 때도 있다.
이는 파라미터와 쿼리로 나뉘어질 수 있는데...

파라미터: /profiles/velopert
쿼리: /about?details=true

이것을 사용하는 것에 대하여 무조건 따라야 하는 규칙은 없지만...

  • 일반적으로는 파라미터는 특정 id 나 이름을 가지고 조회를 할 때 사용하고
  • 쿼리의 경우엔 어떤 키워드를 검색하거나, 요청을 할 때 필요한 옵션을 전달 할 때 사용된다.

※ URL Params

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

/profile/velopert 이런식으로 뒷부분에 username 을 넣어줄 때 해당 값을 파라미터로 받아와보겠다.

src 에 Profile 이라는 컴포넌트를 만들어서 파라미터를 받아오는 예제 코드를 작성해준다.

Profile.js

import React from 'react';
import {useParams} from 'react-router-dom';

// 프로필에서 사용 할 데이터
const profileData = {
  velopert: {
    name: '김민준',
    description:
      'Frontend Engineer @ Laftel Inc. 재밌는 것만 골라서 하는 개발자'
  },
  gildong: {
    name: '홍길동',
    description: '전래동화의 주인공'
  }
};

const Profile = () => {
  const { username } = useParams();
  const profile = profileData[username];
  if (!profile) {
    return <div>존재하지 않는 유저입니다.</div>;
  }
  return (
    <div>
      <h3>
        {username}({profile.name})
      </h3>
      <p>{profile.description}</p>
    </div>
  );
};

export default Profile;

react-router-dom 에 있는 Hook 인 useParams 을 이용해서 하나의 컴포넌트에 변환되는 것을 확인할 수 있다.

그럼 이제 Profile 을 App 에 적용해볼 것 이다.

path 규칙에는 /profiles/:username 이라고 넣어주면 username 에 해당하는 값을 파라미터로 넣어주어서 Profile 컴포넌트에서 match props 를 통하여 전달받을 수 있게 된다.

App.js

import React from 'react';
import { Route, Link, Routes } 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>
      </ul>
      <hr />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/profiles/:username" element={<Profile />} />
      </Routes>
    </div>
  );
};

export default App;

이제 서버에서 /profiles/velopert 경로로 직접 입력하여 들어가보자!

/profiles/gildong 경로도 확인해보면...

잘 출력되는 것을 확인할 수 있다.

※ Query

이번엔 About 페이지에서 쿼리를 받아오겠다. 쿼리는 라우트 컴포넌트에게 props 전달되는 location 객체에 있는 search 값에서 읽어올 수 있다.

location 객체는 현재 앱이 갖고있는 주소에 대한 정보를 지니고 있다.

이런식으로 말이다...

{
  key: 'ac3df4', // not with HashHistory!
  pathname: '/somewhere'
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}

여기서 search 값을 확인해야하는데, 이 값은 문자열 형태로 되어있다. 객체 형태로 변환하는건 우리가 직접 해주어야 한다.

이러한 작업은 qs 라는 라이브러리를 사용하여 쉽게 할 수 있다.

해당 라이브러리를 설치해준다.

$ npm install qs

이제 About 컴포넌트에서 search 값에 있는 detail 값을 받아와서, 해당 값이 true 일때 추가정보를 보여주도록 구현을 해보겠다.

About.js

import React from 'react';
import { useLocation } from 'react-router-dom';
import qs from 'qs';

const About = () => {
  const location = useLocation();
  const query = qs.parse(location.search, {
    ignoreQueryPrefix: true
  });
  const detail = query.detail === 'true'; // 쿼리의 파싱결과값은 문자열입니다.

  return (
    <div>
      <h1>소개</h1>
      <p>이 프로젝트는 리액트 라우터 기초를 실습해보는 예제 프로젝트랍니다.</p>
      {detail && <p>추가적인 정보가 어쩌고 저쩌고..</p>}
    </div>
  );
};

export default About;

/about?detail=true 경로로 들어가보면 추가정보를 확인할 수 있다.

리액트의 Hook 인 useLocation 을 사용해야 에러가 안나고 출력이된다.

참고 : 벨로퍼트와 함께하는 모던 리액트

느낀점 :

  • 오늘은 리액트 라우터에 대해 알아보는 시간을 가졌다.
  • 확실히 싱글 페이지로 작동하다보니 로딩 시간도 없고 편리하다.
profile
하루를 의미있게 살자!

0개의 댓글