๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

โœ๏ธ/React

React ๊ณต๋ถ€ํ•˜๊ธฐ(5) - ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ

react-router๋ฅผ ํ†ตํ•œ ๋ฆฌ์•กํŠธ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ

 

1. ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•

 

$ yarn add react-router-dom

 

ํ”„๋กœ์ ํŠธ์— ๋ผ์šฐํ„ฐ ์ ์šฉ

<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: ํŠน์ • ์ฃผ์†Œ์— ์ปดํฌ๋„ŒํŠธ ์—ฐ๊ฒฐํ•˜๊ธฐ

Link: ๋ˆ„๋ฅด๋ฉด ๋‹ค๋ฅธ ์ฃผ์†Œ๋กœ ์ด๋™์‹œํ‚ค๊ธฐ

import { Route, Link } from 'react-router-dom';
<Route path="์ฃผ์†Œ๊ทœ์น™" component={๋ณด์—ฌ์ฃผ๊ณ ์‹ถ์€ ์ปดํฌ๋„ŒํŠธ}>

<src/App.js>

import React from 'react';
import { Route, 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>
      <hr />
      <Route path="/" exact={true} component={Home} />
      <Route path="/about" component={About} />
      <Route
        path="/profiles"
        exact
        render={() => <div>์œ ์ €๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.</div>}
      /> // render: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ JSX ์ž์ฒด๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.
    </div>
  );
};

export default App;

exact: ํ•ด๋‹น ๊ฒฝ๋กœ๋งŒ ์—ฐ๊ฒฐ (/ O /about X)

 

 

2. ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ์ฟผ๋ฆฌ => ํŽ˜์ด์ง€ ์ฃผ์†Œ ์ •์˜

 

  • ํŒŒ๋ผ๋ฏธํ„ฐ: /profiles/velopert
  • ์ฟผ๋ฆฌ: /about?details=true

์ผ๋ฐ˜์ ์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํŠน์ • id๋‚˜ ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  ์กฐํšŒํ•  ๋•Œ,

์ฟผ๋ฆฌ๋Š” ์–ด๋–ค ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ฑฐ๋‚˜, ์š”์ฒญ์„ ํ•  ๋•Œ ํ•„์š”ํ•œ ์˜ต์…˜์„ ์ „๋‹ฌํ•  ๋•Œ ์‚ฌ์šฉ

 

ํŒŒ๋ผ๋ฏธํ„ฐ

ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋• match ์•ˆ์— ๋“ค์–ด์žˆ๋Š” params ๊ฐ’์„ ์ฐธ์กฐํ•œ๋‹ค.

match ๊ฐ์ฒด ์•ˆ์—๋Š” ํ˜„์žฌ์˜ ์ฃผ์†Œ๊ฐ€ Route ์ปดํฌ๋„ŒํŠธ์—์„œ ์ •ํ•œ ๊ทœ์น™๊ณผ ์–ด๋–ป๊ฒŒ ์ผ์น˜ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.

<src/Profile.js>

const { username } = match.params;

<src.App.js>

<Route path="/profiles/:username" component={Profile} />

 

์ฟผ๋ฆฌ

์ฟผ๋ฆฌ๋Š” ๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ props ์ „๋‹ฌ๋˜๋Š” location ๊ฐ์ฒด์— ์žˆ๋Š” search ๊ฐ’์—์„œ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

location ๊ฐ์ฒด๋Š” ํ˜„์žฌ ์•ฑ์ด ๊ฐ–๊ณ ์žˆ๋Š” ์ฃผ์†Œ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ง€๋‹ˆ๊ณ  ์žˆ๋‹ค.

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

search๊ฐ€ ๋ฌธ์ž์—ด ํ˜•ํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. => qs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ

$ yarn add qs

<src/About.js>

const query = qs.parse(location.search, {
    ignoreQueryPrefix: true
});
const detail = query.detail === 'true'; // ์ฟผ๋ฆฌ์˜ ํŒŒ์‹ฑ๊ฒฐ๊ณผ๊ฐ’์€ ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.

 

 

3. ์„œ๋ธŒ๋ผ์šฐํŠธ (๋ผ์šฐํŠธ ๋‚ด๋ถ€์˜ ๋ผ์šฐํŠธ)

 

 

4. ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ ๋ถ€๊ฐ€๊ธฐ๋Šฅ

 

history ๊ฐ์ฒด

์šฐ๋ฆฌ๊ฐ€ ์ปดํฌ๋„ŒํŠธ ๋‚ด์— ๊ตฌํ˜„ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์—์„œ ๋ผ์šฐํ„ฐ์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. (ex ๋’ค๋กœ๊ฐ€๊ธฐ, ํŠน์ • ๊ฒฝ๋กœ๋กœ ์ด๋™, ์ดํƒˆ ๋ฐฉ์ง€ ๋“ฑ)

<HistorySample.js>

import React, { useEffect } from 'react';

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

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

  useEffect(() => {
    console.log(history);
    const unblock = history.block('์ •๋ง ๋– ๋‚˜์‹ค๊ฑด๊ฐ€์š”?');
    return () => {
      unblock();
    };
  }, [history]);

  return (
    <div>
      <button onClick={goBack}>๋’ค๋กœ๊ฐ€๊ธฐ</button>
      <button onClick={goHome}>ํ™ˆ์œผ๋กœ</button>
    </div>
  );
}

export default HistorySample;

 

withRouter HoC

๋ผ์šฐํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ ๊ณณ์—์„œ match / location / history๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉ

import { withRouter } from 'react-router-dom';

<WithRouterSample.js>

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)} readOnly />
      <h4>match</h4>
      <textarea value={JSON.stringify(match, null, 2)} readOnly />
      <button onClick={() => history.push('/')}>ํ™ˆ์œผ๋กœ</button>
    </div>
  );
};

export default withRouter(WithRouterSample);

 

Switch

์—ฌ๋Ÿฌ Route๋“ค์„ ๊ฐ์‹ธ์„œ ๊ทธ ์ค‘ ๊ทœ์น™์ด ์ผ์น˜ํ•˜๋Š” ๋ผ์šฐํŠธ ๋‹จ ํ•˜๋‚˜๋งŒ์„ ๋ Œ๋”๋ง

=> ์•„๋ฌด๊ฒƒ๋„ ์ผ์น˜ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ๋ณด์—ฌ์ค„ Not Found ํŽ˜์ด์ง€ ๊ตฌํ˜„ ๊ฐ€๋Šฅ!

import { Switch } from 'react-router-dom';

<App.js>

<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>

 

NavLink

ํ˜„์žฌ ๊ฒฝ๋กœ์™€ Link์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ๋กœ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ํŠน์ • ์Šคํƒ€์ผ ํ˜น์€ ํด๋ž™์Šค๋ฅผ ์ ์šฉ

import { NavLink } from 'react-router-dom';

<App.js>

<NavLink
            to="/profiles/velopert"
            activeStyle={{ background: 'black', color: 'white' }}
>

 

๊ธฐํƒ€

  • Redirect: ํŽ˜์ด์ง€๋ฅผ ๋ฆฌ๋””๋ ‰ํŠธ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ
  • Prompt: ์ด์ „์— ์‚ฌ์šฉํ–ˆ๋˜ history.block ์˜ ์ปดํฌ๋„ŒํŠธ ๋ฒ„์ „
  • Route Config: JSX ํ˜•ํƒœ๋กœ ๋ผ์šฐํŠธ๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ Angular ๋‚˜ Vue ์ฒ˜๋Ÿผ ๋ฐฐ์—ด/๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ผ์šฐํŠธ ์ •์˜ํ•˜๊ธฐ
  • Memory Router ์‹ค์ œ๋กœ ์ฃผ์†Œ๋Š” ์กด์žฌํ•˜์ง€๋Š” ์•Š๋Š” ๋ผ์šฐํ„ฐ. ๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ๋‚˜, ์ž„๋ฒ ๋””๋“œ ์›น์•ฑ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์œ ์šฉํ•˜๋‹ค.

 

 

5. useReactRouter Hook ์‚ฌ์šฉํ•˜๊ธฐ

=> ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์„œ ๋ผ์šฐํ„ฐ์— ๊ด€๋ จ๋œ ๊ฐ’(match, history, location ๋“ฑ)๋“ค์„ Hook์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ (๊ณต์‹ X)

=> withRouter๋ž‘ ๋ชฉ์ ์€ ๋น„์Šท

 

$ yarn add use-react-router
import useReactRouter from 'use-react-router';

<RouterHookSample.js>

import useReactRouter from 'use-react-router';

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

export default RouterHookSample;