๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
WEB/Front-End๐ŸŒ

[React JS] Movie App 03 - React Route

by narang111 2021. 12. 5.

React Router

- ํŽ˜์ด์ง€๋ฅผ ์ „ํ™˜ํ•œ๋‹ค.

https://v5.reactrouter.com/web/guides/quick-start

 

Declarative routing for React apps at any scale | React Router

Version 6 of React Router is here! React Router v6 takes the best features from v3, v5, and its sister project, Reach Router, in our smallest and most powerful package yet.

reactrouter.com

 

 

ํ„ฐ๋ฏธ๋„์„ ์ผœ์„œ install ํ•ด์คฌ๋‹ค.

 

์ด์ œ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ์ด๋™์‹œ์ผœ์•ผํ•˜๋Š”๋ฐ ์Šคํฌ๋ฆฐ ๋‹จ์œ„๋กœ ์ƒ๊ฐํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์šฐ๋ฆฌ๋Š” route ๋ณ„๋กœ ์ƒ๊ฐํ•ด์•ผํ•œ๋‹ค. ์Šคํฌ๋ฆฐ, ํŽ˜์ด์ง€, route ๋ถ€๋ฅด๊ณ  ์‹ถ์€๋Œ€๋กœ ๋ถ€๋ฅด์ž

 

 

๋‚ด๊ฐ€ ๋งŒ๋“œ๋Š” app์€ home route๋ฅผ ๋‘๊ณ  ์—ฌ๊ธฐ์„  ๋ชจ๋“  ์˜ํ™”๋ฅผ Movie route๋ฅผ ๋งŒ๋“ค์–ด ํ•˜๋‚˜์˜ ์˜ํ™”๋ฅผ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋‹ค.

 

react project ํด๋”์—์„œ src ํด๋” ์•ˆ์— routes ๋ผ๋Š” ํด๋”์™€ components ํด๋”๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  App ์•ˆ์˜ ๋‚ด์šฉ์„ ์ „๋ถ€ Home.js๋กœ ์˜ฎ๊ฒจ์คฌ๋‹ค.

 

์ด์ œ App.js๋Š” ๋” ์ด์ƒ ์˜ํ™”๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ณ  ๋Œ€์‹ ์— App.js๋Š” router๋ฅผ renderํ•œ๋‹ค.

router๋Š” URL์„ ๋ณด๊ณ ์žˆ๋Š” component๊ณ  ์šฐ๋ฆฌ๊ฐ€ localhost:3000์— ์žˆ๋‹ค๋ฉด Home component๋ฅผ ๋ณด์—ฌ์ค€๋‹ค

์šฐ๋ฆฌ๊ฐ€ localhost:3000/movies ์ด๋ ‡๊ฒŒ ์ ‘์†ํ•œ๋‹ค๋ฉด router์€ Detail component๋ฅผ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋‹ค.

react-router-dom์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡๊ฐ€์ง€๋ฅผ import ํ•ด์•ผํ•œ๋‹ค.

 

 

App.js

์ฝ”๋“œ๋ฅผ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ค€๋‹ค.

import{
  BrowserRouter as Router,
  Switch,
  Route,

} from "react-router-dom";

function App() {
  return null;
}
export default App;

๋ผ์šฐํ„ฐ์—๋Š” hash router, browser router ๋‘๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค.

 

swith๋Š” route๋ฅผ ์ฐพ๋Š” ์ผ์„ ํ•˜๋Š”๋ฐ route๋Š” url์„ ์˜๋ฏธํ•œ๋‹ค.

route๋ฅผ ์ฐพ์œผ๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.

function App() {
  return <Router>
    <Switch>
      <Route>
      	<Home/>
      </Route>
    </Switch>
  </Router>;
}

route์•ˆ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์จ์ค„ ๊ฑด๋ฐ

์˜ˆ๋ฅผ ๋“ค์–ด์„œ 2๊ฐœ์˜ route๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด, ํ•˜๋‚˜๋Š” ์œ ์ €๊ฐ€ ํ™ˆํ™”๋ฉด์œผ๋กœ ๊ฐˆ ๋–„ ์‚ฌ์šฉํ•  route์ด๋‹ค.

path๊ฐ€ "/"๋ผ๋ฉด ํ™ˆ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค 

 

'Switch' is not exported from 'react-router-dom'.

=> ๋ฒ„์ „์ด ๋ฐ”๋€Œ์–ด์„œ ๊ทธ๋Ÿฐ๊ฐ€ ์ด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ๋‹ค.

 

์ด๋ ‡๊ฒŒ ๋ฐ”๊ฟ”์ฃผ์—ˆ๋”๋‹ˆ ์ž˜ ๋œ๋‹ค!

Switch๋ฅผ Routes๋กœ Home ์ปดํฌ๋„ŒํŠธ๋ฅผ element๋กœ ๋„ฃ์–ด์คฌ๋‹ค.

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element= {<Home />}>
          
        </Route>
      </Routes>
    </Router>
  );
}

 

์ƒ์„ธํŽ˜์ด์ง€๋„ ๋˜‘๊ฐ™์ด ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

import {
  BrowserRouter as Router,
  Route,
  Routes

} from "react-router-dom";

import Home from "./routes/Home";
import Detail from "./routes/Detail";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/movie" element= {<Detail />}></Route>
        <Route path="/" element= {<Home />}></Route>
      </Routes>
    </Router>
  );
}
export default App;

 

 

Browser router์™€ hash router๋Š” URL ์ƒ๊น€์ƒˆ์— ์ฐจ์ด๊ฐ€ ์žˆ๋”ฐ.

Browser router๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ‰์†Œ ๋ณด๋Š” url ๊ฐ™๋‹ค

Hash router๋Š” ๋’ค์— /#/ ์ฒ˜๋Ÿผ ๋ญ๊ฐ€ ํ•˜๋‚˜ ๋” ๋ถ™๋Š”๋‹ค. 

 

 

์ด์ œ ํ•˜๊ณ ์‹ถ์€๊ฑด route์—์„œ route๋กœ ์ด๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์œ ์ €๊ฐ€ ์˜ํ™”์ œ๋ชฉ์„ ํด๋ฆญํ•˜๋ฉด ์ด๋™ํ•˜๋„๋ก ํ•˜๊ณ ์‹ถ๋‹ค.

๋‹จ์ˆœ html์ด๋ฉด a link="/movie"๋กœ ํ–ˆ์„ ๊ฒƒ์ด๋‹ค. ๋˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€ ์ „์ฒด๊ฐ€ ์žฌ์‹คํ–‰๋œ๋‹ค.

react์˜ Link ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ์žฌ์‹คํ–‰์„ ๋ง‰๊ณ ์‹ถ๋‹ค

Link๋Š” ๋ธŒ๋ผ์šฐ์ € ์ƒˆ๋กœ๊ณ ์นจ ์—†์ด๋„ ์œ ์ €๋ฅผ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œ์ผœ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.

 

function Movie({coverImg, title, summary, genres}) {
    // App.js์œผ๋กœ๋ถ€ํ„ฐ movie ์ •๋ณด๋ฅผ ๋ฐ›๋Š”๋‹ค
    return (
        <div>
            <img src={coverImg} alt={title} />
            <h2>
                <Link to="/movie">{title}</Link>
            </h2>
            <p>{summary}</p>
            <ul>
                {genres.map((g) => (
                    <li key={g}>{g}</li>
                ))}
            </ul>
        </div>
    );

}

 

 

React Router๋Š” ๋‹ค์ด๋‚˜๋ฏน URL์„ ์ง€์›ํ•ด์ฃผ๊ธฐ๋„ ํ•œ๋‹ค.

๋‹ค์ด๋‚˜๋ฏนํ•˜๋‹ค๋Š”๊ฑด url์— ๋ณ€์ˆ˜๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ์ด๊ฑธ ์ด์šฉํ•ด์„œ ๊ฐ ์˜ํ™”์˜ ์ƒ์„ธํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ด๋‹ค.

/movie/:id ์—ฌ๊ธฐ์— ":" ์จ์ฃผ๋Š”๊ฒŒ ์ค‘์š”ํ•˜๋‹ค. :๊ฐ€ ์—†์œผ๋ฉด "id"๋ผ๋Š” ํ…์ŠคํŠธ ์ž์ฒด๋กœ ๋ณด๋‚ด์ง„๋‹ค.

props ๋กœ id๋„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ถ”๊ฐ€ํ•œ๋‹ค. Home์—์„œ ์ฃผ๊ณ   Movie์—์„œ ๋ฐ›๊ณ 

 

App.js

unction App() {
  return (
    <Router>
      <Routes>
        <Route path="/movie/:id" element= {<Detail />}></Route>
        <Route path="/" element= {<Home />}></Route>
      </Routes>
    </Router>
  );
}

 

Home.js

 

Movie.js

import PropTypes from "prop-types"
import {Link} from "react-router-dom"

function Movie({id, coverImg, title, summary, genres}) {
    // App.js์œผ๋กœ๋ถ€ํ„ฐ movie ์ •๋ณด๋ฅผ ๋ฐ›๋Š”๋‹ค
    return (
        <div>
            <img src={coverImg} alt={title} />
            <h2>
                <Link to={`/movie/${id}`}>{title}</Link>
            </h2>
            <p>{summary}</p>
            <ul>
                {genres.map((g) => (
                    <li key={g}>{g}</li>
                ))}
            </ul>
        </div>
    );

}

Movie.propTypes = {
    id:PropTypes.number.isRequired,
    coverImg: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    summary: PropTypes.string.isRequired,
    genres: PropTypes.arrayOf(PropTypes.string).isRequired
};
export default Movie;

 

 

React Router์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜์ค‘ url์— ์žˆ๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” useParams๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

useParams๋กœ ํ˜„์žฌ ํŽ˜์ด์ง€์˜ url ๋งจ ๋’ค์— ๋ถ™์€ id๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.

์•„๊นŒ :id ์ด๋ ‡๊ฒŒ ์“ด ๋ถ€๋ถ„์—์„œ id๊ฐ€ ๋ณ€์ˆ˜์ด๋‹ค. x๋ผ๋Š” ๋ณ€์ˆ˜์—๋Š” { id:1111 } ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.

function Detail(){
    const x = useParams()
    return <h1>Detail</h1>
}

export default Detail;

 

useParams๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด react router๋Š” ๋ฐ”๋กœ ์ด ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋„˜๊ฒจ์ค€๋‹ค.

https://yts.mx/api/v2/movie_details.json?movie_id= 

 

https://yts.mx/api/v2/movie_details.json?movie_id

 

yts.mx

 

await๋Š” async ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์žˆ์ง€ ์•Š์œผ๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด ํ˜ธ์ถœํ•œ๋‹ค.

import { useEffect } from "react";
import { useParams } from "react-router-dom";
function Detail() {
    const { id } = useParams();
    const getMovie = async () => {
      const json = await (
        await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
      ).json();
      console.log(json);
    };
    useEffect(() => {
      getMovie();
    }, []);
    return <h1>Detail</h1>;
  }
  export default Detail;

 

 

์ด์ œ ์˜ํ™” ์ œ๋ชฉ์„ ํด๋ฆญํ•˜๋ฉด ์ด๋ ‡๊ฒŒ id๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€๋กœ ๊ฐˆ์ˆ˜์žˆ๋‹ค.

'WEB > Front-End๐ŸŒ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Typescript] predictable Typescript  (0) 2021.12.12
[Typescript] ๋ธ”๋ก์ฒด์ธ ๋ฏธ๋‹ˆํ”„๋กœ์ ํŠธ  (0) 2021.12.10
error:03000086:digital envelope routines::initialization error'  (0) 2021.12.04
[React JS] Props type  (0) 2021.12.04
[React JS] Props  (0) 2021.12.04