npm install react-router-dom
yarn add react-router-dom
BrowserRouter 태그로 컴포넌트 사용하기
Routes 태그, Route 태그 컴포넌트 사용하기
Link 태그 컴포넌트 사용하기
문법 : <Link to="경로">링크명</Link>
import { Link } from 'react-router-dom';
React 영화 웹 페이지 만들어보기.
- React router 사용하기.
- 오픈 API 사용해서 데이터 가져오기.
App.js
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from 'pages/Home';
import Detail from 'pages/Detail';
import Navigation from 'components/Navigation';
import Footer from 'components/Footer';
import Search from 'pages/Search';
function App() {
return (
<BrowserRouter>
<Navigation />
<Routes>
<Route path='/' element={<Home />} />
<Route path='/movie/:id' element={<Detail />} />
<Route path='/search/:searchMovie' element={<Search />} />
</Routes>
<Footer />
</BrowserRouter>
);
}
export default App;
📃 Home 페이지
import Movies from 'components/Movies';
import React from 'react';
const Home = () => {
return (
<div>
<Movies />
</div>
);
};
export default Home;
// Movie.js
import React, { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import styles from 'styles/Movie.module.css';
const Movies = () => {
const [movies, setMovies] = useState([]);
const navigate = useNavigate();
const getMovie = () => {
fetch(
'https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year'
)
.then((response) => response.json())
.then((json) => {
const moviesData = json.data.movies;
const slicedMovies = moviesData.slice(0, 8);
setMovies(slicedMovies);
console.log(json.data);
});
};
useEffect(() => {
getMovie();
}, [])
const movieDetailHandle = (id) => {
navigate(`/movie/${id}`);
}
return (
<div>
<div className={styles.movieWrap}>
{movies.map(movie => {
return (
<div key={movie.id} className={styles.movieImg} style={{ backgroundImage: "url(" + `${movie.medium_cover_image}` + ")" }} onClick={() => movieDetailHandle(movie.id)}>
<div className={styles.overlay}>
<div className={styles.head}>
<p>★</p>
<p>{movie.rating} / 10</p>
</div>
<div className={styles.genre}>
<p>{movie.genres}</p>
</div>
<button className={styles.btn}>View Detail</button>
</div>
</div>
)
})}
</div>
</div>
);
};
export default Movies;
📃 Detail 페이지
import MovieDetail from 'components/MovieDetail';
import React from 'react';
import { useParams } from 'react-router-dom';
import styles from 'styles/MovieDetail.module.css';
const Detail = () => {
const { id } = useParams();
return (
<div className={styles.box}>
<MovieDetail id={id} />
</div>
);
};
export default Detail;
//MovieDetail.js
import React, { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import styles from 'styles/MovieDetail.module.css';
const MovieDetail = ({ id }) => {
const [movieDetail, setMovieDetail] = useState({});
const getMovieDetail = () => {
fetch(
`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`
)
.then((response) => response.json())
.then((json) => {
console.log(json.data)
setMovieDetail(json.data.movie);
});
};
useEffect(() => {
getMovieDetail();
}, [])
return (
<div className={styles.wrap}>
<div className={styles.movieDetailWrap}>
<img src={`${movieDetail.medium_cover_image}`} alt="디테일 이미지" className={styles.img} />
<div className={styles.infoWrap}>
<div className={styles.title}>{movieDetail.title}</div>
<div className={styles.year}>{movieDetail.year}</div>
<div className={styles.genres}>{movieDetail.genres}</div>
<span className={styles.rating}>★ {movieDetail.rating} / 10</span>
<span className={styles.download}>⬇ {movieDetail.download_count}</span>
<button className={styles.btn}>⬇ Download</button>
</div>
<div className={styles.info}><h3>줄거리</h3>{movieDetail.description_full}</div>
</div>
</div>
);
};
export default MovieDetail;
📃 검색 페이지
import React, { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import styles from 'styles/Search.module.css'
import stylesMovie from 'styles/Movie.module.css';
const Search = () => {
const { searchMovie } = useParams();
const [searchResults, setSearchResults] = useState([]);
const navigate = useNavigate();
const handleSearch = async () => {
try {
const response = await fetch(
`https://yts.mx/api/v2/list_movies.json?query_term=${searchMovie}`
);
const data = await response.json();
console.log(data.data);
setSearchResults(data.data.movies);
console.log(searchResults);
} catch (error) {
console.log('Error:', error);
}
};
const movieDetailHandle = (id) => {
navigate(`/movie/${id}`);
}
useEffect(() => {
handleSearch();
}, [])
return (
<div className={styles.searchWrap} >
{searchResults.length !== 0 ? (
<div>
<h2><strong>'{searchMovie}' </strong>의 검색 결과는 최대 <strong> {searchResults.length} </strong> 건 입니다.</h2>
<div className={stylesMovie.movieWrap} style={{justifyContent: 'center'}}>
{searchResults.map(movie => {
return (
<div key={movie.id} className={stylesMovie.movieImg} style={{ backgroundImage: "url(" + `${movie.medium_cover_image}` + ")" , marginRight:'20px'}} onClick={() => movieDetailHandle(movie.id)}>
<div className={stylesMovie.overlay}>
<div className={stylesMovie.head}>
<p>★</p>
<p>{movie.rating} / 10</p>
</div>
<div className={stylesMovie.genre}>
<p>{movie.genres}</p>
</div>
<button className={stylesMovie.btn}>View Detail</button>
</div>
</div>
)
})}
</div>
</div>
) : (
<div>
<h1>검색 결과가 없습니다 ㅠ..ㅠ</h1>
</div>
)}
</div>
);
};
export default Search;
일단 먼저 useState()로 상태 관리 하는 법과 useEffect()를 이용해 특정 작업을 수행하는 법에 대해 많이 익숙해진 것 같다. 또한 오픈 API를 이용해 데이터가 어떤 식으로 요청 응답이 되는지 알 수 있었다.
부족한점은 아직 화면 레이아웃 잡는 법과 스타일링이 부족한 것 같다.