[React] 06. SPA ์™€ Router

์†ก์šฐ๋“ ยท2021๋…„ 6์›” 9์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
6/23
post-thumbnail

๐Ÿ’š SPA(Single Page Application)

๋‹จ์ผ ํŽ˜์ด์ง€๋กœ ์ด๋ฃจ์–ด์ง„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

์ „ํ†ต์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŽ˜์ด์ง€๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”๋ฐ์š”. ์ด๋Ÿฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ์ž๋Š” ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด HTML์„ ๋ฐ›์•„์•ผํ–ˆ๋Š”๋ฐ์š”. ์ ์  ์›น์—์„œ ์ œ๊ณตํ•˜๋Š” ์ •๋ณด๊ฐ€ ๋งŽ์•„์ง€๋ฉด์„œ ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ ์ธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๋ฆฌ์•กํŠธ์™€ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ทฐ ๋ Œ๋”๋ง์„ ๋‹ด๋‹น์‹œํ‚ค๊ณ , ์‚ฌ์šฉ์ž์™€์˜ ์ธํ„ฐ๋ ‰์…˜์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ํ•˜๋ฉฐ ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SPA๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง€๋Š” ํ•œ ์ข…๋ฅ˜์ด์ง€๋งŒ, ํ•ด๋‹น ํŽ˜์ด์ง€์—์„œ ๋กœ๋”ฉ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํ˜„์žฌ ์‚ฌ์šฉ์ž ๋ธŒ๋ผ์šฐ์ €์˜ ์ฃผ์†Œ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ํ™”๋ฉด์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ๋ผ์šฐํŒ…(Routing)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’š ๋ผ์šฐํ„ฐ(Router)

๋‹ค๋ฅธ ์ฃผ์†Œ(url)์— ๋‹ค๋ฅธ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ
<Router>๋Š” <Switch>์™€ <Route>์— ๊ณตํ†ต ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ

๋จผ์ €, ๋ผ์šฐํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ํ”„๋กœ์ ํŠธ์— react-router-dom๋ฅผ ์„ค์น˜ํ•ด์ค๋‹ˆ๋‹ค.

npm install react-router-dom --save

++ ์ถ”๊ฐ€์ ์œผ๋กœ react-router ์™€ react-router-dom ์ฐจ์ด์ 

react-router-dom : ์›น์šฉ ์ปดํฌ๋„ŒํŠธ ํฌํ•จ
react-router-native : react-native๋ฅผ ํ™œ์šฉํ•œ ์•ฑ์šฉ ์ปดํฌ๋„ŒํŠธ ํฌํ•จ
react-router : ์›น/์•ฑ ๋‘˜๋‹ค ํฌํ•จ

๋จผ์ €, <Link>์ปดํฌ๋„ŒํŠธ์™€ <Route>์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ •๋ฆฌํ•˜๊ณ  ์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด๋ก ํ• ๊ฒŒ์š”!

๐Ÿ’›๋งํฌ(Link)์ปดํฌ๋„ŒํŠธ

<Link>์ปดํฌ๋„ŒํŠธ๋Š” HTML์— <a>ํƒœ๊ทธ์™€ ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ํ•˜๋Š”๋ฐ์š”! <Link>๋Š” to์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋™ํ•  ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<Link to="/">HOME ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ธฐ</Link>
<Link to="/intro">INTRO ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ธฐ</Link>

๐Ÿ’›๋ผ์šฐํŠธ(Route)์ปดํฌ๋„ŒํŠธ

<Route>์ปดํฌ๋„ŒํŠธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ˜„์žฌ URL์— ๋”ฐใ…ใ„น ํŠน์ • ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ์ˆจ๊ธฐ๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋˜๋Š”๋ฐ์š”.

<Route path="/" component={Home} exact={true} />
<Route path="/intro" component={Intro} />

<Route>์ปดํฌ๋„ŒํŠธ์— component์†์„ฑ์„ ์ด์šฉํ•ด ํ™”๋ฉด์— ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, path์†์„ฑ์— url์„ ์ง€์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, ์—ฌ๋Ÿฌ url์—์„œ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ์—๋Š” ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”!

<Route component={Intro} path={["/intro", "/info"]} />

์•„๋ž˜ ์ฝ”๋“œ๋Š” <Link>์™€ <Route>๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:)
์ถ”๊ฐ€์ ์œผ๋กœ <Switch>๋Š” <Route>๋“ค ์ค‘์— ์กฐ๊ฑด์— ๋งž๋Š” ํ•˜๋‚˜์˜ ๋ผ์šฐํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š”๋ฐ์š”.

import { BrowserRouter, Link } from "react-router-dom";
import { Route, Switch } from "react-router";
import Home from "./page/Home";
import Intro from "./page/Intro";
import NotFound from "./page/NotFound";

const AppRouter = () => {
return (
  <BrowserRouter>
    <Link to="/">HOME ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ธฐ</Link>
    <br />
    <Link to="/intro">INTRO ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ธฐ</Link>
    <Switch>
      <Route path="/" component={Home} exact={true} />
      <Route path="/intro" component={Intro} />
      <Route component={NotFound} />
    </Switch>
  </BrowserRouter>
);
};

export default AppRouter;

๐Ÿ’š url ํŒŒ๋ผ๋ฏธํ„ฐ ์‚ฌ์šฉํ•˜๊ธฐ

๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ๋‚˜ ์š”์ฒญํ•  ๋•Œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ์š”. <Route>์ปดํฌ๋„ŒํŠธ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ €, userId๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์™€ ํ•ด๋‹น user์˜ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” Profile์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

  import React from "react";

const users = {
  1: { name: "์†ก์šฐ๋“ ", description: "Front-end Dev" },
  2: { name: "๋จน๊นจ๋น„", description: "Back-end Dev" },
};

const Profile = ({ match }) => {
  const { userId } = match.params;

  const user = users[userId];
  return (
    <div>
      <h1> PROFILE PAGE </h1>
      <p>{user.name}์ž…๋‹ˆ๋‹ค!</p>
      <p>{user.description}</p>
    </div>
  );
};

export default Profile;

์—ฌ๊ธฐ์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ์—๋Š” match๊ฐ์ฒด ์•ˆ์— params๊ฐ’์„ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. match๊ฐ์ฒด ์•ˆ์—๋Š” ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋–ค ๊ฒฝ๋กœ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์œ„์— AppRouter์ปดํฌ๋„ŒํŠธ์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
์ง€์ •ํ•  ํŒŒ๋ผ๋ฏธํ„ฐ ์•ž์— :์„ ๋ถ™์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” userId๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ฃผ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— :userId๋ฅผ ๋ถ™์—ฌ์ฃผ์—ˆ์–ด์š”!

<Route path="/profile/:userId" component={Profile} />

๐Ÿ’š url ์ฟผ๋ฆฌ ์‚ฌ์šฉํ•˜๊ธฐ

์ด๋ฒˆ์—” ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ฟผ๋ฆฌ๋Š” location ๊ฐ์ฒด์— ์žˆ๋Š” "search"๊ฐ’์—์„œ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ์š”! ์ด location๊ฐ์ฒด์—๋Š” ํ˜„์žฌ ์•ฑ์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ฃผ์†Œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”ป locationํ˜•ํƒœ ์˜ˆ์‹œ

"search"๊ฐ’์€ ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ๋˜์–ด ์žˆ๋Š”๋ฐ์š”. ์ด๋Ÿฐ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด qs๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

npm install qs --save  

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ค๋‹ˆ๋‹ค. admin๊ฐ’์— true / false์—ฌ๋ถ€์— ๋”ฐ๋ผ ํ™”๋ฉด์— ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

import React from "react";
import qs from "qs";
 
const ManageUser = ({location}) => {

   const query = qs.parse(location.search, {
       ignoreQueryPrefix: true
   });

   const isAdmin = query.admin === 'true';

   return (
       <div>
           <h1>ADMIN PAGE</h1>
           {isAdmin && <p>๊ด€๋ฆฌ์ž ์ž…๋‹ˆ๋‹ค.</p>}
           {!isAdmin && <p>๊ด€๋ฆฌ์ž ์•„๋‹™๋‹ˆ๋‹ค.</p>}
       </div>
   );
};

export default ManageUser;

์ฐธ๊ณ  ์ž๋ฃŒ ๋ฐ ์‚ฌ์ดํŠธ

๋ฒจ๋กœํ”ผํŠธ์™€ ํ•จ๊ป˜ํ•˜๋Š” ๋ชจ๋˜ ๋ฆฌ์•กํŠธ

profile
๊ฐœ๋ฐœ ๊ธฐ๋ก๐Ÿ’ป

0๊ฐœ์˜ ๋Œ“๊ธ€