movie app λ§λ€κΈ°
App.js νμΌμ νκΊΌλ²μ μμ±νλ μ½λλ€μ λλ΄λ€.
src/routes/ μμ Home.jsμ Detail.js νμΌμ μμ±νλ€.
src/components/ μμ Movie.js νμΌμ μμ±νλ€.
npm i react-router-dom
// App.js
import { BrowserRouter, Routes, Route } from "react-router-dom"; // μ΄ μ»΄ν¬λνΈλ€μ urlμ λ°λΌλ³΄κ³ μλ€
import Home from "./routes/Home";
import Detail from "./routes/Detail";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} /> {/* μ¬μ©μκ° root(/)μ μμΌλ©΄ <Home /> μ»΄ν¬λνΈλ₯Ό λ λλ§ */}
<Route path="/movie" element={<Detail />} /> {/* μ¬μ©μκ° /movieλ‘ μ΄λνλ©΄ <Detail /> μ»΄ν¬λνΈλ₯Ό λ λλ§ */}
</Routes>
</BrowserRouter>
);
}
export default App;
νμ΄μ§λ₯Ό μ΄λνκ³ μ ν λ a νκ·Έλ₯Ό μ΄μ©ν΄λ λμ§λ§ μ΄λ κ² λλ©΄ μ μ²΄κ° μλ‘κ³ μΉ¨ λλ€.
react-routerμ Linkλ₯Ό μ΄μ©νλ©΄ μλ‘κ³ μΉ¨ μμ΄ νμ΄μ§λ₯Ό μ΄λν μ μλ€.
// Movie.js
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
function Movie({index, title, rating, genres, summary}) {
return (
<div>
<h2 style={{ display: "inline" }}>{index + 1}. <Link to="/movie">{title}</Link></h2>
<span> - νμ {rating}μ </span>
<ul>{genres.map((genre) => <li key={genre}>{genre}</li>)}</ul>
<p>{summary}</p>
</div>
);
}
Movie.propTypes = {
index: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
rating: PropTypes.number.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
summary: PropTypes.string.isRequired,
};
export default Movie;
μ½λ μ±λ¦°μ§
νμ¬ μ¬μ©μκ° Homeμμ μν μ λͺ©(http: //localhost:3000/movie)μ λλ₯΄λ©΄ Detail μ»΄ν¬λνΈλ κ·Έμ < h1>Detail</ h1> μ λ°ννκ³ μλ€.
μ΄λν νμ΄μ§μμ ν΄λΉ μνμ λν μ 보λ₯Ό 보μ¬μ£ΌκΈ° μν΄μλ, μ΄λν νμ΄μ§μμ fetchλ₯Ό μ΄μ©ν΄ https:// yts.mx/api/v2/movie_details.json?movie_id=...λ‘λΆν° λ°μ΄ν°λ₯Ό κ°μ ΈμμΌ νλ€.
κ·Έλ°λ° urlμ λ§μ§λ§μλ κ°κ°μ movie.idμ κ°μ λ£μ΄μ€μΌ νλ€.
movie.idμ κ°μ κ° νμ΄μ§μμ url νλΌλ―Έν°λ₯Ό μ΄μ©ν΄ λ°μμ¬ μ μλ€.
// App.js
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movie/:id" element={<Detail />} /> // π‘ :id μΆκ°
</Routes>
</BrowserRouter>
);
}
export default App;
Routeκ° μ§μΌλ³΄κ³ μλ urlμΈ /movieλ₯Ό /movie/:idλ‘ μμ νλ€.
idμλ μ΄λ€ κ°μ΄λ μ¬ μ μλ€.
μ¬μ©μκ° /movie/:id λ‘ μ΄λνλ©΄ Detail μ»΄ν¬λνΈκ° λ λλ§λλ€.
// Detail.js
import { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import Movie from "../components/Movie";
function Detail() {
const { id } = useParams(); // π‘ useParams() === { id: ... }
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState({});
const getMovie = async() => {
const json = await (await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)).json();
setMovie(json.data.movie);
setLoading(false);
};
useEffect(() => getMovie(), []);
return (
<div>
{/* π‘ 첫 μ»΄ν¬λνΈ λ λλ§ μ μμ§ λΉλκΈ° μμ
μ΄ λλμ§ μμ movieμ κ°μ {}μ΄λ€.
μ΄λ‘ μΈν΄ λͺ¨λ propμ΄ undefinedκ° λμ΄ PropTypesμ μν΄ μ½μ μ°½μ κ²½κ³ κ° λ¬λ€. loading λ³μλ₯Ό μ΄μ©νλ μ΄μ μ΄λ€. */}
{ loading
? <strong>λ‘λ© μ€μ
λλ€...</strong>
: <Movie
id={movie.id}
title={movie.title_long}
rating={movie.rating}
genres={movie.genres}
summary={movie.description_full}
/>
}
</div>
);
}
export default Detail;
useParamsλ₯Ό μ΄μ©ν΄ url νλΌλ―Έν° idμ κ°μ λ°μμ€κ³ λλ©΄ λλ¨Έμ§λ Home μ»΄ν¬λνΈμ λμΌν λ‘μ§μ κ±°μ³ λ λλ§ κ³Όμ μ΄ μ§νλλ€.
μ΄ μ¬μ΄μ css μμ λ νλ€.
npm i gh-pages
build ν ν deploy ν΄μΌ νλ€.
npm run deployλ§ μ
λ ₯ν΄λ μλμΌλ‘ buildκ° μ§νλλλ‘ deployμ λλΆμ΄ predeploy scriptλ₯Ό μΆκ°νλ€.
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"deploy": "gh-pages -d build",
"predeploy": "npm run build"
}
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState({});
const getMovie = async() => {
const json = await (await fetch("...")).json();
setMovie(json.data.movie);
setLoading(false);
console.log(movie); // 1λ² μ½μλ‘κ·Έ
};
useEffect(() => getMovie(), []);
console.log(movie); // 2λ² μ½μλ‘κ·Έ
return (
<div>
{ loading
? <strong>λ‘λ© μ€μ
λλ€...</strong>
: <Movie title={movie.title_long} />
}
</div>
);
}
export default Detail;
μ μ½λμ μ€ν κ²°κ³Ό
λ΄κ° μ΄ν΄ν λ°λ λ€μκ³Ό κ°λ€.
λ¨Όμ , νμ΄μ§κ° μ²μ μ΄λ¦¬κ³ μμ§ fetchκ° μλ£λκΈ° μ μ Detail μ»΄ν¬λνΈ λ λλ§μ΄ μ§νλΌμ 2λ² μ½μλ‘κ·Έ μμΉμμ λΉ λ°°μ΄ [] μ΄ μΆλ ₯λλ€.
fetchλ₯Ό μλ£ν ν setMovie(json.data.movie)μ μν΄ λ¦¬λ λλ§μ΄ μΌμ΄λκ³ movie stateκ° λ°λμκΈ° λλ¬Έμ 2λ² μ½μλ‘κ·Έ μμΉμμ 20[...] κ° μΆλ ₯λλ€.
λ§μ°¬κ°μ§λ‘ setLoading(false)μ μν΄ λ¦¬λ λλ§μ΄ μΌμ΄λκ³ loading stateκ° λ°λμκΈ° λλ¬Έμ 2λ² μ½μλ‘κ·Έ μμΉμμ 20[...] κ° μΆλ ₯λλ€.
λ§μ§λ§μΌλ‘ getMovie ν¨μ λ³Έλ¬Έ μμμ console.log(movie), μ¦ 1λ² μ½μλ‘κ·Έκ° μ€νλλ€.
πββοΈ μ¬κΈ°μ μμ κ³Όμ κ³Ό μ°κ³ν΄μλ μ νν μ λΉ λ°°μ΄ [] μ΄ μΆλ ₯λλ κ±΄μ§ λͺ¨λ₯΄κ² λ€.