본문 바로가기

Frontend/React

2021-04-30 :: 리액트 라우터로 SPA 개발하기2

URL 쿼리

이번에는 About 페에지에서 쿼리를 받아 오겠습니다. 쿼리는 location 객체에 들어 있는 search 값에서 조회할 수 있다. location 객체는 라우트로 사용된 컴포넌트에게 props로 전달되며, 웹 어플리케이션의 현재 주소에 대한 정보를 지니고 있다. location의 형태는 다음과 같다.

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

위 location 객체는 URL/about?deatail=true 주소로 들어갔을 때의 값이다. URL 쿼리를 읽을 때는 위 객체가 지닌 값 중에서 search 값을 확인해야 한다. 이 값은 문자열 형태로 되어 있다. 또한 URL 쿼리는 ?detail=true&another=1과 같이 문자열에 여러 가지 값을 설정해 줄 수 있다. search 값에서 특정 값을 읽어 오기 위해서는 이 문자열을 객체 형태로 변환해 주어야 한다.

쿼리 문자열을 객체로 변환할 때는 qs라는 라이브러리를 사용한다. yarn을 통해 해당 라이브러리를 설치해보자.

$ yarn add qs
import React from 'react';
import qs from 'qs';

const About = ({location}) => {
   const query = qs.parse(location.search, {
      ignoreQueryPrefix: true
   });
   const showDetail = query.detail === 'true';
   return(
      <div>
         <h1>소개</h1>
         <p>이 프로젝트에서 리액트 라우터 기초를 실습한다.</p>
         {showDetail && <p>detail 값을 true로 설정하셨네요!</p>}
      </div>
   );
};

export default About;

쿼리를 사용할 때는 쿼리 문자열을 객체로 파싱하는 과정에서 결과 값은 항상 문자열이라는 점에 주의하자. ?value=1 혹은 ?value=true와 같은 값을 전달 받아도 파싱 후 "1", "true"와 같이 문자열 형태로 받아진다.

그렇기 때문에 숫자를 받는 경우는 parseInt 함수를 통해 꼭 숫자로 변환해 주고, 논리 자료형 값인 경우에는 "true"문자열과 비교하여 사용하자.

서브 라우트

서브 라우트는 라우트 내부에 또 라우트를 정의하는 것을 의미한다. 이 작업은 그냥 라우트로 사용되고 있는 컴포넌트의 내부에 Route 컴포넌트를 또 사용하면 된다.

profiles라는 라우트 컴포넌트를 따로 만들고, 그 안에서 profile 컴포넌트를 서브 라우트로 사용하도록 코드를 작성해 보겠다.

import React from 'react';
import {Link, Route} from 'react-router-dom';
import Profile from './Profile';

const Profiles = () => {
   return(
      <div>
         <ul>
            <li>
               <Link to="/profiles/seyoung8239">seyoung</Link>
            </li>
            <li>
               <Link to="/profiles/asdf">mandoo</Link>
            </li>
         </ul>

         <Route
            path="/profiles"
            exact
            render={()=><div>사용자를 선택해 주세요.</div>}
         />
         <Route path="/profiles/:username" component={Profile}/>
      </div>
   )
}

export default Profiles;

 

리액트 라우터 부가 기능

history

history 객체는 라우트로 사용된 컴포넌트에 match, location과 함께 전달되는 props 중 하나로, 이 객체를 통해 컴포넌트 내에 구현되는 메서드에서 라우터 API를 호출할 수 있다. 예를 들어 뒤로가기 버튼, 로그인 후 화면 전환, 다른 페이지로의 이탈 방지를 구현할 때 history를 이용한다

import React, {Component} from 'react';

class HistorySample extends Component {
   hadnleGoBack = () => {
      this.props.history.goBack();
   };
   
   hadnleGoHome = () => {
      this.props.history.push('/');
   };

   componentDidMount = () => {
      this.unblock = this.props.history.block('정말 떠나실 건가요?');
   };

   componentDidMount() {
      if(this.unblock)
         this.unblock();
   }

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

export default HistorySample;

withRouter

withRouter 함수는 HoC(higher-order Component)이다. 라우트로 사용된 컴포넌트가 아니어도 match, location, history 객체를 접근할 수 있게 해 준다.

import React from 'react';
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
         />
         <h4>match</h4>
         <textarea 
            value={JSON.stringify(match, null, 2)}
            rows={7}
            readOnly
         />
         <button onClick={()=>history.push('/')}>홈으로</button>
      </div>
   );
}

export default withRouter(WithRouterSample);

JSON.stringify의 두 번째 파라미터와 세 번째 파라미터를 위와 같이 null, 2로 설정해 주면 JSON에 들여쓰기가 적용된 상태로 문자열이 만들어진다.

Switch

switch컴포넌트는 여러 Route를 감싸서 그중 일치하는 단 하나의 라우트만 렌더링 시켜준다. swtich를 사용하면 모든 case와 일치하지 않을 때 보여 줄 Not Found 페이지도 구현 가능하다.

<Switch>
  <Route path="/" component={Home} exact={true}/>
  <Route path={['/about', '/info']} component={About}/>
  <Route path='/profiles' component={Profiles}/>
  <Route path='/history' component={HistorySample}/>
  <Route 
    render={({location})=>(
      <div>
        <h2>이 페이지는 존재하지 않습니다:</h2>
        {location.pathname}
      </div>
    )}
  />
</Switch>

NavLink

NavLink는 Link와 비슷하다. 현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 CSS 클래스를 적용할 수 있는 컴포넌트이다.

NavLink에서 링크가 활성화되었을 때의 스타일을 적용할 때는 activeStyle 값을, CSS 클래스를 적용할 때는 activeClassName 값을 props로 넣어주면 된다.