React : Router, Params, Build, Deploy

<angeLog/>ยท2024๋…„ 2์›” 23์ผ

REACT

๋ชฉ๋ก ๋ณด๊ธฐ
11/25
post-thumbnail

๐Ÿ’ก๋…ธ๋งˆ๋“œ์ฝ”๋” ๋‹ˆ๊ผฌ์Œค์˜ ๊ฐ•์˜๋ฅผ ๋ณด๋ฉฐ ๊ณต๋ถ€ํ•˜๋Š” ์‹œ๋ฆฌ์ฆˆ์ž…๋‹ˆ๋‹ค.

ReactRouter Install

npm install react-router-dom
๊ฐ•์˜์˜์ƒ์€ @5.3.0์˜€์ง€๋งŒ ๋ณธ์ธ์€ @6.22.1์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.
์ผ๋‹จ ๊ฐ•์˜๋Œ€๋กœ ์ง„ํ–‰ํ•˜๊ฒŒ ๋„ ๋•Œ ๋งž์ดํ•˜๊ฒŒ๋˜๋Š” ๋ช‡๊ฐ€์ง€ issue๋“ค์ด ์žˆ๋Š”๋ฐ, Switch๊ฐ€ Routes๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค. ๊ณต์‹๋ฌธ์„œ Client side routing ์ฐธ๊ณ .
๐Ÿ‘‰๐ŸปFeature Overview v6.22.1

Route์˜ ๋ฐฉ์‹๋„ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค.
๊ธฐ์กด์—๋Š” <Route><์ปดํฌ๋„ŒํŠธ></Route>ํ˜•์‹์œผ๋กœ ์‚ฌ์šฉ๋˜์—ˆ์ง€๋งŒ v6์ด์ƒ ๋ถ€ํ„ฐ๋Š” Route์— element๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ผ์šฐํŒ…ํ•œ๋‹ค. ๋˜ํ•œ ์ด์ƒํƒœ๋กœ build๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด ํŽ˜์ด์ง€์— ์ ‘์†ํ–ˆ์„ ๋•Œ ๋นˆํŽ˜์ด์ง€๋งŒ์ด ๋ณด์—ฌ์ง€๊ฒŒ ๋˜๋ฏ€๋กœ Router์— basename={process.env.PUBLIC_URL}์„ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค.

//App.js์˜ˆ์‹œ
import {
  BrowserRouter as Router,
  Routes,
  Route,
} from 'react-router-dom';
import PageHome from './routes/PageHome';

function App() {
  return (
    <Router basename={process.env.PUBLIC_URL}>
      <Routes>
        <Route path="/" element={<PageHome />} />
      </Routes>
    </Router>
  );
}
export default App;

vue๋งŒ ์‚ฌ์šฉํ•ด๋ณธ ๋‚ด ์ž…์žฅ์—์„œ ๋ณธ react์˜ routing์€ ํ˜์‹ ์ด๋‹ค.
vue2, vue3๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•ด๋ณด๊ณ , vue2์™€ vue3๋ชจ๋‘ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๊นŒ์ง€ ํ•ด ๋ณด์•˜์ง€๋งŒ route ์ด๊ฒŒ ์ƒ๊ฐ๋ณด๋‹ค ๊ท€์ฐฎ๊ธฐ๋„ ํ•˜๊ณ  ๊นŒ๋‹ค๋กญ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋Š”๋ฐ react์˜ routing์€ ๋ง ๊ทธ๋Œ€๋กœ ์ถฉ๊ฒฉ์ ์ด๋‹ค.
๊ตณ์ด route.js๋ฅผ ๋งŒ๋“ค์–ด์„œ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ค„์ง€ ์ผ์ผ์ด ์„ค์ •์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š”๊ฒŒ ๋„ˆ๋ฌด๋„ˆ๋ฌด ํŽธ๋ฆฌํ•˜๊ณ  ์ข‹๋‹ค!

vue์˜ route.js์—์„œ ์ด๋Ÿฐ ์ผ๋ จ์˜ ๊ณผ์ •์„ ์ง€๋‚œ ๋‹ค์Œ์— ๊ฐ ํŽ˜์ด์ง€ ๋ณ„๋กœ path๋ฅผ ๋˜ ์ง€์ •ํ•ด์•ผํ–ˆ๋‹ค๋ฉด react์—์„œ๋Š” ๊ทธ๋ƒฅ Page์—์„œ ๋ฐ”๋กœ routinge ํ•ด๋ฒ„๋ฆฌ๋ฉด ๋๋‚œ๋‹ค.

Link
Link๋Š” Router์™€ ๊ฐ™์€ react-router-dom์ด ์ œ๊ณตํ•˜๋Š” component์ด๋‹ค.
routing์„ ํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ์ด ๋˜๋Š”๋ฐ react์˜ ์žฅ์ ์„ ์‚ด๋ ค์„œ ์ ๋‹นํ•œ ์‹œ์ ์— Link๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ ์—†์ด ์›ํ•˜๋Š” ํŽ˜์ด์ง€๊ฐ€ render๋œ๋‹ค.
๋‹จ, App.js์—์„œ Link๋กœ Routeํ•  component๋ฅผ ๊ผญ importํ•ด์•ผํ•œ๋‹ค.

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

function Movie() {
  return (
    <div>
      <h1>
        <Link to="/movie">{ํƒ€์ดํ‹€}</Link>
      </h1>
    </div>
  );
}

BrowserRouter, HashRouter

url์—์„œ ์ฐจ์ด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
http://localhost:3000/movie : BrowserRouter,
http://localhost:3000/#/movie : HashRouter

Dynamic URL : Params๋„˜๊ธฐ๊ธฐ

URL์— Params๋ฅผ ๊ฐ™์ด ๋„˜๊ฒจ์„œ Params์— ๋งž๋Š” data๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ• ๋˜ํ•œ ์‰ฝ๋‹ค.
path="/์นดํ…Œ๊ณ ๋ฆฌ/:params" ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด movie์นดํ…Œ๊ณ ๋ฆฌ์—์„œ id๋”ฐ๋ผ ๋ณด์—ฌ์ง€๋Š” detailPage๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด, path="/movie/:id"๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด ๋œ๋‹ค.

์˜ˆ์‹œ : App.js

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<PageHome />} />
        //๋ฐ˜๋“œ์‹œ :id๋กœ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค. id๋กœ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ id๋Š” ๊ฐ’์ด์•„๋‹Œ ๋ฌธ์žid๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
        <Route path="/movie/:id" element={<PageDetail />} />
      </Routes>
    </Router>
  );
}

์˜ˆ์‹œ : Index.js

<์ปดํฌ๋„ŒํŠธ
  key={movie.id}
  propCover_image={movie.medium_cover_image}
  propTitle={movie.title}
  propSummary={movie.summary}
  propGenres={movie.genres}
  //props๋กœ ์š”์†Œ์˜ id๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
  propGId={movie.id}
  />

์˜ˆ์‹œ : Detail.js

useParams
React Router๊ฐ€ ์ œ๊ณตํ•˜๋Š” Hook์ด๋ฉฐ, <Route path>๋ฅผ ํ†ตํ•ด ํ˜„์žฌ์˜ url์— ๊ฐ์ฒด์˜ key/value๋ฅผ ์Œ์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜dynamic params์ด๋‹ค.

//์ตœ์ƒ๋‹จ์— useParam import
import { useParams } from 'react-router-dom';
function Detail() {
  const x = useParams();
  console.log('x', x);
  return <h1>๋””ํ…Œ์ผ ํŽ˜์ด์ง€</h1>;
}
export default Detail;

์‘์šฉ

ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š” ๋””ํ…Œ์ผ ํŽ˜์ด์ง€๋ผ๋Š” ๊ธ€์ž๋ฅผ id์— ๋งž๋Š” ์˜ํ™” ์ œ๋ชฉ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•œ๋‹ค.

import { useParams } from 'react-router-dom';
import { useEffect, useState } from 'react';

function PageDetail() {
  const { id } = useParams();
  const [movie, setMovie] = useState([]);
  async function getData() {
    const response = await fetch(
      `https://yts.mx/api/v2/movie_details.json?movie_id=${id}`
    );
    const jsonData = await response.json();
    setMovie(jsonData.data.movie);
  }
  useEffect(() => getData(), []);
  return <h1>{movie.title}</h1>;
}
export default PageDetail;

fetch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ api๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  data๋ฅผ ๊ฐ€์ ธ์™”๋‹ค.
useEffect๋กœ api๋Š” ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๋„๋ก ํ•˜๊ณ , state์˜ title๋ฅผ ํ™”๋ฉด์— ๋ฟŒ๋ ค์คฌ๋‹ค.

์˜๋„ํ•œ๋Œ€๋กœ ํ™”๋ฉด์— title์ด ๋ณด์—ฌ์ง€์ง€๋งŒ ์ฝ˜์†”์— ์—๋Ÿฌ๊ฐ€ ๋ณด์—ฌ์ง„๋‹ค.

hint

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]);

์ฃผ์–ด์ง„ ํžŒํŠธ๋Œ€๋กœ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž.
์˜๋„ํ•œ ๋Œ€๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

Build

๊ฐ•์˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“  movie-app์„ ๋ฐฐํฌํ•ด๋ณด์ž.

PUBLISHING
Install npm i gh-pages
github์—์„œ ๋ฌด๋ฃŒ๋กœ ์ œ๊ณตํ•ด์ฃผ๋Š” ํŒจํ‚ค์ง€๋กœ, ๊ฒฐ๊ณผ๋ฌผ์„ github pages์— ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค€๋‹ค.

package.json์˜ script๋ถ€๋ถ„์—๋Š” deploy, predeploy ์ถ”๊ฐ€ํ•˜๊ณ , ์ตœํ•˜๋‹จ์— homepage๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
์Šคํฌ๋ฆฝํŠธ ๋””ํ”Œ๋กœ์ด, ํ”„๋ฆฌ๋””ํ”Œ๋กœ์ด ์ถ”๊ฐ€. ์ตœํ•˜๋‹จ homepage ์ถ”๊ฐ€.

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "deploy": "gh-pages -d build",
    "predeploy": "npm run build"
  },
  "homepage": "https://๊นƒํ—™์•„์ด๋””.github.io/๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ด๋ฆ„"

predeploy๋Š” npm run deploy ์‹คํ–‰ ํ–ˆ์„ ๋•Œ build๊ฐ€ ๋˜๋„๋ก ํ•˜๋Š” ์˜ต์…˜์œผ๋กœ, ํ•ด๋‹น ์˜ต์…˜์ด ์—†์œผ๋ฉด build๊ฐ€ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์•„๋งˆ๋„ 404error๊ฐ€ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.
ํ„ฐ๋ฏธ๋„์—์„œ npm run deploy ํ•˜๋ฉด ๋จผ์ € build๊ฐ€ ๋œ ์ดํ›„ ์ž๋™์œผ๋กœ ๊นƒํ—™ ํŽ˜์ด์ง€์— ๋ฐฐํฌ๋œ๋‹ค.

๐Ÿ‘‰๐ŸปMOVIEFLEX

profile
์ผ๋‹จ ํ•ด๋ณผ๊ฒŒ์š”!โœ๐Ÿป

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