[Velopert리액트5]리액트 라우터

Yongrok·2021년 12월 29일
0

React_Velopert

목록 보기
6/9

사용교재 : 벨로퍼트와 함께하는 모던 리액트
범위 : 5.1 ~ 5.5
노션 용량문제로 Migration

리액트 라우터

SPA - 라우터 관계

SPA라면 페이지가 하나란 뜻인데, 왜 라우터로 페이지를 나눌까?

  • 주소를 나눠야 홈, 목록, 포스트, 글쓰기 등 기능을 분리할 수 있다
  • 주소를 나눠야 필요한 부분을 북마크 가능
  • 구글 유입이 가능

단점

SPA) 앱의 규모가 커짐 → JS 파일 커짐 → 렌더링 속도 저하 → 코드 스플팅으로 해결가능

라우터) JS 실행 전에는 정보X , JS 캐싱 전에는 빈 화면 → SSR로 해결가능

1. 기본 사용법

라우터 적용

BrowserRouter 컴포넌트로 감싸기

// ./src/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();

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

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

// ./src/App.js
import React from 'react';
import { Route } 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;

⇒ 이 경우 //home 에도 포함되기 때문에, 두 페이지가 동시에 나타난다!

→ 해결법) exact !

exact

해당 속성이 true일 때, Route 컴포넌트는 경로가 정확히 일치할때만 연결시켜준다.

컴포넌트 클릭시 다른 주소로 이동시킨다.

(!) 리액트 라우터에서는 a 태그를 사용하면 안 된다
→ 정 쓰고 싶다면 onClick 이벤트로 관리한 뒤, 주소를 변경시켜주자
a 태그는 주소 이동 후, 페이지를 새로 불러오기 때문

→ 리액트 상태 초기화! ㄷㄷ

사용법

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to="/"></Link>
        </li>
        <li>
          <Link to="/about">소개</Link>
        </li>
      </ul>
      <hr />
      <Route path="/" exact={true} component={Home} />
      <Route path="/about" component={About} />
    </div>
  );
};

2. 파라미터, 쿼리

  • 파라미터 : 특정 id, 이름으로 조회할 때. /users/yrk
  • 쿼리 : 특정 키워드 검색, 요청할 때 필요한 옵션 전달. /about?details=true
  • 정해진 규칙은 아니다

URL Params

// ./src/App.js
const App = () => {
  return (
    <div>
      <Route path="/profiles/:username" component={Profile} />
    </div>
  );
};

// ./src/Profile.js
const profileData = {
  gildong: {
    name: '홍길동',
    description: '전래동화의 주인공'
  },
	//...
};

const Profile = ({ match }) => {
  // 파라미터를 받아올 땐 match 안에 들어있는 params 값을 참조.
  const { username } = match.params;
  const profile = profileData[username];
  if (!profile) {
    return <div>존재하지 않는 유저입니다.</div>;
  }
  return (
    <div>
      <h3>
        {username}({profile.name})
      </h3>
      <p>{profile.description}</p>
    </div>
  );
};

export default Profile;

match ?

*{path: "/profiles/:username", url: "/profiles/velopert", isExact: true, params: Object}
1. path: "/profiles/:username"
2. url: "/profiles/velopert"
3. isExact: true
4. ▶params: Object
    1. username: "velopert"*

⇒ 그 상위는?

*{match: Object, location: Object, history: Object, staticContext: undefined}
1. ▶match: Object
2. ▶location: Object
    1. pathname: "/profiles/velopert"
    2. search: ""
    3. hash: ""
    4. state: undefined
3. ▶history: Object
    1. length: 1
    2. action: "POP"
    3. ▶location: Object
    4. ▶createHref: *ƒ createHref() {}*
        
    5. ▶push: *ƒ push() {}*
        
    6. ▶replace: *ƒ replace() {}*
        
    7. ▶go: *ƒ go() {}*
        
    8. ▶goBack: *ƒ goBack() {}*
        
    9. ▶goForward: *ƒ goForward() {}*
        
    10. ▶block: *ƒ block() {}*
        
    11. ▶listen: *ƒ listen() {}*
        
4. staticContext: undefined*

Query

라우트 컴포넌트에 props로 전달되는 location 객체의 search 값에서 조회가능

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

qs 라이브러리

Query를 문자열에서 객체로 변환

1) qs.parse(location.search.substr(1));

2) qs.parse(location.search, {ignoreQueryPrefix: true});

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

⬇️

{detail: "true"}

3. 서브라우트

라우트 내부의 라우트

장점

  • setState 불필요
  • 링크를 통해 다른 곳에서 쉽게 진입 가능
  • 검색엔진 크롤링 효율高
// ./src/Profiles.js
const Profiles = () => {
  return (
    <div>
      <Route
        path="/profiles"
        exact
        render={() => <div>유저를 선택해주세요.</div>}
      />
      <Route path="/profiles/:username" component={Profile} />
    </div>
  );
};

// App.js
const App = () => {
  return (
    <div>
      <Route path="/" exact={true} component={Home} />
      <Route path="/about" component={About} />
      <Route path="/profiles" component={Profiles} />
    </div>
  );
};

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

History 객체

라우트로 사용된 컴포넌트에게 전달되는 props 중 하나
이 객체를 통해 컴포넌트 내에 구현한 메소드 → 라우트 직접 접근 가능
(뒤로가기, 특정 경로로 이동, 이탈 방지 등)

function HistorySample({ history }) {
  const goBack = () => {
    history.goBack();
  };

  const goHome = () => {
    history.push('/');
  };

  useEffect(() => {
    console.log(history);
    const unblock = history.block('정말 떠나실건가요?');
    return () => {
      unblock();
    };
  }, [history]);
//...
}
  • props ?
{match: Object, location: Object, history: Object, staticContext: undefined}
	match: Object
	location: Object
	history: Object
		length: 6
		action: "PUSH"
		location: Object
		createHref: ƒ createHref() {}
		push: ƒ push() {}
		replace: ƒ replace() {}
		go: ƒ go() {}
		goBack: ƒ goBack() {}
		goForward: ƒ goForward() {}
		block: ƒ block() {}
		listen: ƒ listen() {}

withRouter HoC

라우트 컴포넌트가 아닌 곳에서 match, location, history 를 사용해야 할 때 사용

라우트 컴포넌트 아니지만, 자신 부모 기준의 라우트 props 가 전달됨

// ./src/WidthRouterSample.js
import { withRouter } from 'react-router-dom';
const WithRouterSample = ({ location, match, history }) => {
//...
};

export default withRouter(WithRouterSample);

Switch

여러 Route 들을 감싸서 그 중 규칙이 일치하는 단 하나의 라우트를 렌더링
→ 일치하는 것이 없을시 Not Found페이지 구현가능

const App = () => {
  return (
    <div>
      <Switch>
        <Route path="/" exact={true} component={Home} />
        <Route path="/about" 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>
  );
};

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

사용법 : 컴포넌트에 activeStyle 속성을 통해 css 로 스타일링한다

<NavLink to="/profiles/gildong" activeStyle={{ color: 'red' }}>

activeClassName 을 통해 클래스명 부여도 가능

그 외

  • Redirect : 페이지 리다이렉트
  • Prompt : history.block 의 컴포넌트 버전
  • Route Config : 배열, 객체를 사용하여 라우트 정의 → useRoutes v6
  • Memory Router : 실제로 주소는 존재하지는 않는 라우터

5. useReactRouter 훅

라우트로 사용되지 않는 컴포넌트에서 라우트 관련 props를 조회하는 훅(withRouter)

사용 라이브러리 : use-react-router

import useReactRouter from 'use-react-router';

function RouterHookSample() {
  const { history, location, match } = useReactRouter;
  console.log({ history, location, match });
  return null;
}

export default RouterHookSample;

→ 이후 릴리즈~

useHistory , useLocation, useParams, useRouteMatch 등장 (from react-router-dom)

0개의 댓글