React.js - 리액트 라우터(React Router)

Gyu·2022년 6월 3일
0

React.js

목록 보기
13/20
post-thumbnail

react-router

  • 다른 주소에서 다른 화면을 보여주는 것을 라우팅이라고 한다.
  • 클라이언트 사이드에서 이루어지는 라우팅을 구현하여 SPA를 쉽게 만들어 주는 라이브러가 react-router다.

react-router 설치 및 적용

  • 설치 : npm install react-router-dom
  • 프로젝트에 라우터 적용
    • 프로젝트에 리액트 라우터를 적용할 때는 src/index.js 파일에서 react-router-dom에 내장되어 있는 BroswerRouter 컴포넌트를 사용해서 루트 컴포넌트를 감싸면 된다.

    • BroswerRouter 컴포넌트는 웹 애플리케이션에 HRML5의 History API를 사용하여 페이지를 새로고침 하지 않고도 주소를 변경하고, 현재 주소에 관련된 정보를 props로 쉽게 조회하거나 사용할 수 있도록 해준다.

      import React from 'react';
      import ReactDOM from 'react-dom';
      import { BrowserRouter } from 'react-router-dom' // 1. import react-router-dom
      import './index.css';
      import App from './App';
      
      ReactDOM.render( // 2. 루트 컴포넌트를 BrowserRouter 컴포넌트로 감싸기
        <BrowserRouter> 
          <App />
        </BrowserRouter>,
        document.getElementById('root')
      );

Route 컴포넌트

  • Router 컴포넌트를 사용하면 어떤 규칙을 가진 경로에 어떤 컴포넌트를 보여 줄지 정의할 수 있다.
    // Router 컴포넌트 사용 방식
    <Router path="주소규칙" component={보여줄 컴포넌트}/>
  • 예시
    import React from 'react';
    import { Route } from 'react-router-dom'; // Router 컴포넌트 불러오기
    import Home from './components/Home';
    import About from './components/About';
    
    function App() {
      return (
        <div>
          <Route path="/" component={Home} exact={true}/>
          <Route path="/about" component={About}/>
        </div>
      );
    }
    
    export default App;
    • 첫 화면에는 Home 컴포넌트 렌더링이 되고, /about 경로로 이동시 Home 컴포넌트와 About 컴포넌트가 렌더링된다. 이는 /about 경로가 / 규칙에도 일치하기 때문이다. 이를 수정하기 위해 주소가 /인 Router 컴포넌트에 exact 라는 props를 true 로 설정해준다.
  • Link 컴포넌트는 클릭하면 다른 주소로 이동시켜주는 컴포넌트다. a 태그를 사용해도 페이지 전환이 되지만 그 경우 페이지를 새로 불러오기 때문에 애플리케이션이 갖고 있는 모든 상태가 초기화된다.
  • Link 컴포넌트를 사용하여 페이지를 전환하면, 페이지를 새로 불러오지 않고 애플리케이션은 그대로 유지한 상태에서 HTML5 History API를 사용하여 페이지의 주소만 변경해준다. Link 컴포넌트 자체는 a 태그로 이루어져 있지만, 페이지 전환을 방지하는 기능이 내장되어 있다.
    <Link to="주소">내용</Link>
  • 예제
    import React from 'react';
    import { Route, Link } from 'react-router-dom'; // Link 컴포넌트 불러오기
    import Home from './components/Home';
    import About from './components/About';
    
    function App() {
      return (
        <div>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
          </ul>
          <Route path="/" component={Home} exact={true}/>
          <Route path="/about" component={About}/>
        </div>
      );
    }
    
    export default App;

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

  • Route 하나에 여러 개의 path 를 지정하는 것은 최신 버전의 리액트 라우터 v5부터 적용된 기능이다.
    // 이전 버전 - Router 두 번 사용
    <Route path="/" component={Home} exact={true}/>
    <Route path="/about" component={About}/>
    <Route path="/info" component={About}/>
    
    // 최신 버전 - path props를 배열로 설정하면 여러 경로에 같은 컴포넌트를 보여줄 수 있다.
    <Route path="/" component={Home} exact={true}/>
    <Route path={ ['/about', '/info'] } component={About}/>

URL 파라미터와 쿼리 스트링

  • 페이지 주소를 정의할 때 가끔 유동적인 값을 전달해야할 때가 있다. 이는 파라미터와 쿼리스트링으로 나뉠 수 있다.
    • url 파리미터 예시 : /profile/velopert
    • 쿼리 스트링 예시 : /about?detail=true
  • 라우터로 쓰인 컴포넌트는 props로 match, location, history를 전달받는다. matchhistory 객체로 url 파리미터와 쿼리스트링을 처리할 수 있다.

URL 파라미터

  • url 파라미터를 사용할 때는 라우트로 사용되는 컴포넌트에서는 match 객체를 props로 받아와 사용해야 한다. match 객체는 현재 컴포넌트가 어떤 경로 규칙에 의해 보이는지에 대한 정보가 들어있다. url 파라미터의 값은 match 안에 params 값에 들어있다.
  • url 파라미터를 받아서 처리하는 컴포넌트
    const Compnent = ({ match }) => { // match를 props로 받아옴
    	const { param } = match.params; // match.params에 url 파라미터에 대한 정보다 담겨있다.
    }
    
    /* 
    props.match = {
    	isExact: true
    	params: {username: "gyu"}  => url 파라미터
    	path: "/profile/:username"  => 경로 규칙
    	url: "/profile/gyu  => 실제 url
    }
    */"
  • 라우트 정의 컴포넌트
    // Route 컴포넌트
    <Route path="/주소/:변수" component={컴포넌트}/>
    
    // Link 컴포넌트
    <Link to="/주소/값">내용</Link>
    
    /*
    라우트 정의 컴포넌트에서 이렇게 설정하면
    url 파라미터를 받아서 처리하는 컴포넌트에서는
    match.params = { 변수: 값 }로 받아 사용할 수 있다.
    */
  • // Profile.js
    import React from 'react';
    
    const data = {
        gyu: {
            name: 'Lee',
            description: '코린이...'
        },
        gildong: {
            name: '홍길동',
            description: '홀길동도롱도롱롱롱롱'
        }
    }
    
    const Profile = ({match}) => {
        console.log(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;
    
    // App.js
    import React from 'react';
    import { Route, Link } from 'react-router-dom';
    import Profile from './components/Profile';
    
    function App() {
      return (
        <div>
          <ul>
            <li>
              <Link to="/profile/gyu">gyu's profile</Link>
            </li>
            <li>
              <Link to="/profile/gildong">gildong's profile</Link>
            </li>
          </ul>
          <Route path="/profile/:username" component={Profile}/>
        </div>
      );
    }

쿼리 스트링

  • 라우터로 쓰인 컴포넌트에서 location 객체를 props로 전달을 수 있다. location 객체는 웹 어플리케이션의 현재 주소에 대한 정보를 갖고 있다.
    // location 객체 예 - /about?detail=true
    {
    	hash: ""
    	key: "wq2uka"
    	pathname: "/about"
    	search: "?detail=true"
    	state: undefined
    }
  • 쿼리스트링을 확인할 때는 location 객체의 search의 값을 확인해야한다. 이 값은 문자열로 되어있는데, 쿼리 스트링의 특정 값을 확인하기 위해서는 qs 라이브러리를 사용해서 search 값을 객체로 바꿔줘야한다.
  • // About.js
    import React from 'react';
    import qs from 'qs'; // qs 라이브러리 설치 및 불러오기
    
    const About = ({location}) => {
        const query = qs.parse(location.search, {
            ignoreQueryPrefix: true // search 문자열 맨 앞의 ?를 생략하는 옵션
        })
        const showDetail = query.detail === 'true'; // 쿼리 파싱값은 문자열
        return (
            <div>
               <h1>소개</h1>
               <p>이 프로젝트는 리액트 라우터 기초를 실습해보는 예제 프로젝트입니다.</p>
               {showDetail && <p>detail 값을 true로 설정하셨군요!</p>}
            </div>
        );
    };
    
    export default About;
    
    // App.js
    <Link to="/about?detail=true">About</Link>

서브라우트

  • 라우트 내부에 또 라우트를 정의하는 것. 라우트로 사용되고 있는 컴포넌트 내부에 Route 컴포넌트를 사용하는 것.
  • // App.js
    import React from 'react';
    import { Route, Link } from 'react-router-dom';
    import ProfileWrapper from './components/ProfileWrapper';
    
    function App() {
      return (
        <div>
          <ul>
            <li>
              <Link to="/profile">profiles</Link>
            </li>
          </ul>
          <Route path="/profile" component={ProfileWrapper}/>
        </div>
      );
    }
    
    export default App;
    
    // ProfileWrapper.js
    import React from 'react';
    import { Route, Link } from 'react-router-dom';
    import Profile from './Profile'
    
    const ProfileWrapper = () => {
        return (
            <div>
                <h3>사용자 목록 : </h3>
                <ul>
                    <li>
                        <Link to="/profile/gyu">gyu's profile</Link>
                    </li>
                    <li>
                        <Link to="/profile/gildong">gildong's profile</Link>
                    </li>
                </ul>
                <Route
                    path="/profile"
                    exact
                    render={()=><div>사용자를 선택해 주세요.</div>}
                />
                <Route path="/profile/:username" component={Profile} />
            </div>
        );
    };
    
    export default ProfileWrapper;
    
    /*
    JSX에서 props를 설정할 때 값을 생략하면 자동으로 true로 설정된다.
    때문에 exact={true}는 exact와 같다.
    
    Route 컴포넌트에 component 대신 render라는 props를 넣었다.
    render는 컴포넌트 자체가 아닌 보여주고 싶은 JSX를 반환하는 함수를 넣어
    컴포넌트를 만들기 애매한 상황이나, 컴포넌트에 별도의 props를 넣어주고 싶을 때 사용한다. 
    */

리액트 라우터 부가 기능

History

  • history 객체는 라우르로 사용된 컴포넌트에 match, location과 함께 전달되는 props 중 하나로, 이 객체를 통해 컴포넌트 내에 구현하는 메서드에서 라우터 API를 호출 할 수 있다.
  • 사용법
    history.goBack() // 뒤로가기
    history.push('rout') // 특정 라우트로 이동

withRouter

  • withRouter함수는 리액트 라우트에서 제공하는 HoC(Higher-order Component)다. 라우트로 사용된 컴포넌트가 아니어도 match, location, history 객체에 접근할 수 있게 해준다.
  • import React from 'react';
    import { withRouter } from 'react-router-dom'; // 1. withRouter 불러오기
    const WithRouterSample = ({ location, match, history }) => { 
      return (              // 2. props로 location, match, history 받아오기
        <div>
          <h4>location</h4>
          <textarea
            value={JSON.stringify(location, null, 2)}
            rows={7}
            readOnly={true}
          />
          <h4>match</h4>
          <textarea
            value={JSON.stringify(match, null, 2)}
            rows={7}
            readOnly={true}
          />
          <button onClick={() => history.push('/')}>홈으로</button>
        </div>
      );
    };
    
    export default withRouter(WithRouterSample); 
    // 3. 컴포넌트를 export할 때 withRouter 함수로 감싸주기
    
    // * JSON.stringify()함수의 두, 세번째 매개변수에 null, 2를 넣으면 
    //   JSON에 들여쓰기 된 상태로 문자열이 생성됨

💡 고차 컴포넌트(HOC, Higher Order Component)

컴포넌트를 인자로 받아서 컴포넌트를 반환하는 함수로 컴포넌트 로직을 재사용하기 위한 React의 고급 기술이다.

Switch

  • Switch 컴포넌트는 여러 Route 컴포넌트를 감싸서 그중 일치하는 단 하나의 라우트만을 렌더링 시켜준다. Switch 컴포넌트를 사용하면 모든 규칙에 일치하지 않을 때 보여줄 Not Found 페이지도 구현이 가능하다.
  • import React from 'react';
    import { Route, Link, Switch } from 'react-router-dom';
    import About from './About';
    import Home from './Home';
    import Profiles from './Profiles';
    import HistorySample from './HistorySample';
    
    const App = () => {
      return (
        <div>
          <ul>
            <li>
              <Link to="/"></Link>
            </li>
            <li>
              <Link to="/about">소개</Link>
            </li>
            <li>
              <Link to="/profiles">프로필</Link>
            </li>
            <li>
              <Link to="/history">History 예제</Link>
            </li>
          </ul>
          <hr />
          <Switch>
            <Route path="/" component={Home} exact={true} />
            <Route path={['/about', '/info']} component={About} />
            <Route path="/profiles" component={Profiles} />
            <Route path="/history" component={HistorySample} />
            <Route
              // path를 따로 정의하지 않으면 모든 상황에 렌더링됨
              render={({ location }) => (
                <div>
                  <h2>이 페이지는 존재하지 않습니다:</h2>
                  <p>{location.pathname}</p>
                </div>
              )}
            />
          </Switch>
        </div>
      );
    };
    
    export default App;
  • NavLink 컴포넌트는 Link 컴포넌트와 비슷하다. 현재 경로와 Link 컴포넌트에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 css 클래스를 적용할 수 있는 컴포넌트.
  • NavLink에서 링크가 활성화 되었을 때 스타일을 적용하고 싶다면 activeStyle을, css 클레스 이름을 적용하고 싶다면 activeClassName을 props로 넣어주면 된다.
  • import React from 'react';
    import { NavLink, Route } 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" active>
                velopert
              </NavLink>
            </li>
            <li>
              <NavLink activeStyle={activeStyle} to="/profiles/gildong">
                gildong
              </NavLink>
            </li>
          </ul>
    
          <Route
            path="/profiles"
            exact
            render={() => <div>유저를 선택해주세요.</div>}
          />
          <Route path="/profiles/:username" component={Profile} />
        </div>
      );
    };
    
    export default Profiles;
profile
애기 프론트 엔드 개발자

0개의 댓글