뭐할지 고민하다가 노마드코더를 들어가보니 function component로 영화 웹 서비스를 업데이트 해서 겸사겸사 다시 들었다 😃 오~ 색달라! 여하튼.. 중간중간 블로깅을 했어야했는데.. 어쩌다보니 다 만들고 올린다...ㅎㅎ 🙄
👉 css를 안입힌 최종결과물
//App.js
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./routes/Home";
import Detail from "./routes/Detail";
function App() {
return (
<Router>
{/* 스위치는 route를 찾는 역할 */}
<Switch>
{/* router에 이 url이 변수를 받을거라고 말해주는것 */}
<Route path="/movie/:id">
<Detail />
</Route>
{/*Home이 메인! path="/"를 하면 index 페이지라 생각하면된다.*/}
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
App은 딱히 뭐가 없어서 router만 적고 넘어갔다...
//Home.js
import { useState, useEffect } from "react";
import Movie from "../components/Movie";
function Home() {
const [loading, setLoading] = useState(true);
const [movies, setMovies] = useState([]);
//async, await를 사용할 때
const getMovies = async () => {
{/* 👇 async, await를 좀 더 간단하게 표현한것 */}
const json = await (
await fetch(
`https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year`
)
).json();
{/* 👇 위의 코드를 풀어쓰면 이렇게 된다. */}
// const res = await fetch(
// `https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year`
// );
// const json = await res.json();
setMovies(json.data.movies);
setLoading(false);
};
useEffect(() => {
getMovies();
}, []);
//fetch를 사용할 때
// useEffect(() => {
// fetch(
// `https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year`
// )
// .then((res) => res.json())
// .then((json) => {
// setMovies(json.data.movies);
// setLoading(false);
// });
// }, []);
return (
<>
{/* json을 받아오기 전엔 loading이 나오고 다 받아왔다면 정보들을 보여준다! */}
{loading ? (
<h1>Loading..</h1>
) : (
<div>
{movies.map((movie) => (
<Movie
key={movie.id}
id={movie.id}
coverImg={movie.medium_cover_image}
title={movie.title}
summary={movie.summary}
genres={movie.genres}
/>
))}
</div>
)}
</>
);
}
export default Home;
Home에선 async, await를 사용했는데, 아직 익숙하지가 않아서.. fetch로 쓰는게 좋긴하다....
//Movie.js
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
{/* 이곳에서 props를 받아서 표현해준다. coverImg는 medium_cover_image를 props로 넘겨줄때 coverImg로 넘겨줘서 넘겨준 이름 그대로 받아서 쓴것 */}
function Movie({ coverImg, title, summary, genres, id }) {
return (
<div>
{/* alt를 안쓰면 친절하게 알려준다.. */}
<img src={coverImg} alt={title} />
<h2>
{/* react에서 id에 따라 url을 바꿔주고싶다면 아래와 같이 사ㅛㅇ하면 된다. */}
<Link to={`/movie/${id}`}>{title}</Link>
</h2>
<p<>{summary}</p>
<ul>
{/* genres는 없을수도 있을수도 있기 때문에 옵셔널 체이닝을 걸었고, 여러개가 있기에 map을 돌렸당 */}
{genres?.map((g) => (
<li key={g}>{g}</li>
))}
</ul>
</div>
);
}
{/* id에 string이 들어간다면 너 그렇게 쓰지마! 하고 알려주는 기능 (타입스크립트를 쓴다면 무시해도 될 부분이다.) */}
Movie.prototype = {
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;
🤔 ts를 안쓴다면 prototype도 괜찮은것같당
//Detail.js
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
function Detail() {
const { id } = useParams();
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
{/* api에서 id를 기준으로 해당 movie의 정보를 불러오게한다. */}
const getMovie = async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setLoading(false);
{/* 불러온 정보를 담아서 나타내주는 준비운동? 같은 느낌*/}
setMovie(json.data.movie);
};
useEffect(() => {
getMovie();
}, []);
return (
<>
{/* 정보를 가져오기 전까진 loading이 나오고 가져왔다면 영화 정보들이 나온다. */}
{loading ? (
<h1>loading..</h1>
) : (
<div>
<img src={movie.medium_cover_image} alt={movie.title} />
<h2>{movie.title}</h2>
<p>{movie.date_uploaded}</p>
<ul>
{movie.genres?.map((g) => (
<li key={g}>{g}</li>
))}
</ul>
</div>
)}
</>
);
}
export default Detail;
흠,, 🤔 스타일링을 하면 또 오랫동안 붙잡아둘까봐 기능만 후딱하고 끝내버렸다.. 우선 useEffect의 기능과 useState의 기능을 다시 개념을 잡아보는 시간이여서 좋았다. (하지만 Dynamic Routing은 한번 더 보는거로...😅)