2swan
React Router 예제(함수 방식) 본문
App.js
import {BrowserRouter, Route, Routes} from "react-router-dom"
import './App.css';
import Home from './routers/Home';
import About from "./routers/About";
import Navigation from "./components/Navigation";
import Poster from "./routers/Poster";
import Detail from "./routers/Detail";
function App() {
return (
<BrowserRouter>
<Navigation/>
<Routes>
<Route path={"/"} element={<Home/>}></Route>
<Route path={"/about"} element={<About/>}></Route>
<Route path={"/poster"} element={<Poster/>}></Route>
<Route path={"/detail"} element={<Detail/>}></Route>
</Routes>
</BrowserRouter>
);
}
export default App
App.css
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
'Open Sans', 'Helvetica Neue', sans-serif;
background-color: #eff3f7;
height: 100%;
}
Movie.css
// components 폴더
.movies .movie {
background-color: white;
margin-bottom: 70px;
font-weight: 300;
padding: 20px;
border-radius: 5px;
color: #adaeb9;
box-shadow: 0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3),
0 -6px 16px -6px rgba(0, 0, 0, 0.025);
}
.movies .movie a {
display: grid;
grid-template-columns: minmax(150px, 1fr) 2fr;
grid-gap: 20px;
text-decoration: none;
color: inherit;
}
.movie img {
position: relative;
top: -50px;
max-width: 150px;
width: 100%;
margin-right: 30px;
box-shadow: 0 30px 60px -12px rgba(50, 50, 93, 0.25), 0 18px 36px -18px rgba(0, 0, 0, 0.3),
0 -12px 36px -8px rgba(0, 0, 0, 0.025);
}
.movie .movie__title,
.movie .movie__year {
margin: 0;
font-weight: 300;
}
.movie .movie__title {
margin-bottom: 5px;
font-size: 24px;
color: #2c2c2c;
}
.movie .movie__genres {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
margin: 5px 0px;
}
.movie__genres li,
.movie .movie__year {
margin-right: 10px;
font-size: 14px;
}
Movie.js
// components 폴더
import { Link } from 'react-router-dom';
import './Movie.css';
const Movie = ({title, year, summary, poster, genres}) => {
return(
<div className="movie">
<img src={poster} alt={title} title={title}/>
<div className="movie_data">
<h3 className="movie_title">app06 {title}</h3>
<h5 className="movie_year">{year}</h5>
<ul className="moive_genres">
{
genres.map((genre,index)=>{
return(
<li key={index}>
{genre}
</li>
)
})
}
</ul>
<p>{summary.slice(0,100)}...</p>
<Link to={'/detail'}
state={{year, title, summary, poster, genres}}>
Detail
</Link>
</div>
</div>
)
}
export default Movie;
Navigation.css
// components 폴더
.nav {
z-index: 1;
position: fixed;
top: 50px;
left: 10px;
display: flex;
flex-direction: column;
background-color: white;
padding: 10px 20px;
box-shadow: 0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3),
0 -6px 16px -6px rgba(0, 0, 0, 0.025);
border-radius: 5px;
}
@media screen and (max-width: 1090px) {
.nav {
left: initial;
top: initial;
bottom: 0px;
width: 100%;
}
}
.nav a {
text-decoration: none;
color: #0008fc;
text-transform: uppercase;
font-size: 12px;
text-align: center;
font-weight: 600;
}
.nav a:not(:last-child) {
margin-bottom: 20px;
}
Navigation.js
// components 폴더
import {Link} from "react-router-dom";
import "./Navigation.css"
function Navigation(){
return(
<div className="nav">
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/poster">Poster</Link>
</div>
)
}
export default Navigation;
About.css
// routers 폴더
.about__container {
box-shadow: 0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3),
0 -6px 16px -6px rgba(0, 0, 0, 0.025);
padding: 20px;
border-radius: 5px;
background-color: white;
margin: 0 auto;
margin-top: 100px;
width: 100%;
max-width: 400px;
font-weight: 300;
}
.about__container span:first-child {
font-size: 20px;
}
.about__container span:last-child {
display: block;
margin-top: 10px;
}
Aboout.js
// routers 폴더
import './About.css'
const About = ()=>{
return(
<div className="about_container">
<span>app06_About</span><br/>
<span>2023</span>
</div>
)
}
export default About
Detail.js
// routers 폴더
import { useLocation } from 'react-router-dom'
import './MovieView.css'
const Detail=()=>{
const location = useLocation();
console.log({location})
return(
<div className='movie_container'>
<img src={location.state.poster}
alt={location.state.title} title={location.state.title}/>
<div className='movie_data'>
<h3 className='movie_title'>app06 {location.state.title}</h3>
<h5 className='movie_year'>{location.state.year}</h5>
<ul className='movie_genres'>
{
location.state.genres.map((genre, index)=>{
return(
<li key={index}>
{genre}
</li>
)
})
}
</ul>
</div>
</div>
)
}
export default Detail;
Home.css
// routers 폴더
.container {
height: 100%;
display: flex;
justify-content: center;
}
.loader {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-weight: 300;
}
.movies {
display: grid;
grid-template-columns: repeat(2, minmax(400px, 1fr));
grid-gap: 100px;
padding: 50px;
width: 80%;
padding-top: 70px;
}
@media screen and (max-width: 1090px) {
.movies {
grid-template-columns: 1fr;
width: 100%;
}
}
Home.js
// routers 폴더
import React, { useEffect, useState} from 'react';
import axios from 'axios';
import './Home.css'
import Movie from '../components/Movie';
const Home = ()=>{
const [movies, setMovies] = useState([])
const [isLoading, setLoading] = useState(true)
const getMoives =()=>{
axios.get('https://yts.mx/api/v2/list_movies.json?sort_by=rating')
.then((res)=>{
console.log("res.data:", res.data)
setMovies(res.data.data.movies)
setLoading(false)
})
}
//componentDidMount, componentDidUpdate
useEffect(()=>{
getMoives()
},[])
return(
<section className='container'>
{
isLoading ? (
<div className='loader'>
<span>isLoading</span>
</div>
) : (
<div className='movies'>
{
movies.map((movie)=>{
return(
//사진, title, year, genres, summary
<Movie key={movie.id}
year = {movie.year}
title = {movie.title}
summary = {movie.summary}
poster = {movie.medium_cover_image}
genres = {movie.genres}
/>
)
})
}
</div>
)
}
</section>
)
}
export default Home;
MovieView.css
// routers 폴더
.movie__container {
box-shadow: 0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3),
0 -6px 16px -6px rgba(0, 0, 0, 0.025);
padding: 20px;
border-radius: 5px;
background-color: white;
margin: 0 auto;
margin-top: 100px;
width: 100%;
max-width: 400px;
font-weight: 300;
}
.movie__container span:first-child {
font-size: 20px;
}
.movie__container span:last-child {
display: block;
margin-top: 10px;
}
.movie img {
position: relative;
top: -50px;
max-width: 150px;
width: 100%;
margin-right: 30px;
box-shadow: 0 30px 60px -12px rgba(50, 50, 93, 0.25), 0 18px 36px -18px rgba(0, 0, 0, 0.3),
0 -12px 36px -8px rgba(0, 0, 0, 0.025);
}
.movie .movie__title,
.movie .movie__year {
margin: 0;
font-weight: 300;
}
.movie .movie__title {
margin-bottom: 5px;
font-size: 24px;
color: #2c2c2c;
}
.movie .movie__genres {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
margin: 5px 0px;
}
.movie__genres li,
.movie .movie__year {
margin-right: 10px;
font-size: 14px;
}
Navigation.css
// routers 폴더
.nav {
z-index: 1;
position: fixed;
top: 50px;
left: 10px;
display: flex;
flex-direction: column;
background-color: white;
padding: 10px 20px;
box-shadow: 0 13px 27px -5px rgba(50, 50, 93, 0.25), 0 8px 16px -8px rgba(0, 0, 0, 0.3),
0 -6px 16px -6px rgba(0, 0, 0, 0.025);
border-radius: 5px;
}
@media screen and (max-width: 1090px) {
.nav {
left: initial;
top: initial;
bottom: 0px;
width: 100%;
}
}
.nav a {
text-decoration: none;
color: #0008fc;
text-transform: uppercase;
font-size: 12px;
text-align: center;
font-weight: 600;
}
.nav a:not(:last-child) {
margin-bottom: 20px;
}
Poster.js
// routers 폴더
import axios from "axios";
import { useEffect, useState } from "react";
import './Home.css';
const Poster = () => {
const [movies, setMovies] = useState([]);
const [isLoading, setLoading] = useState(true);
const getMovies = () => {
axios.get('https://yts.mx/api/v2/list_movies.json?sort_by=rating')
.then((res) => {
console.log("res.data:", res.data);
setMovies(res.data.data.movies);
setLoading(false);
})
}
useEffect(() => {
getMovies();
}, []);
return (
<section className="container">
{
isLoading ? (
<div className="loader">
<span>Loading</span>
</div>
) : (
<div className="movies">
{
movies.map((movie) => (
<img key={movie.id}
src={movie.medium_cover_image}
alt={movie.title}
/>
))}
</div>
)}
</section>
);
}
export default Poster;
'Programming > React' 카테고리의 다른 글
React Login 예제 (0) | 2023.10.14 |
---|---|
React Router 예제(Class 방식) (0) | 2023.09.12 |
React DB 연결(Mybatis) (0) | 2023.09.11 |
React 추가, 삭제(Mybatis) (0) | 2023.09.11 |
React DB 연결(JPA) (0) | 2023.09.11 |