Movie App 배포 및 라우팅
배포
npm install -s gh-pages
우선 gh-pages를 설치하자.
gh-pages는 웹사이트를 깃허브의 도메인에 나타나도록 해준다.
도메인의 형식은 (사용자 이름).github.io/(프로젝트 이름)이다. 기억이 나지 않는다면 'git remote -v'로 확인할 수 있다.
나의 경우는 https://leeeeeyeon.github.io/yeonmovie_frontend/이다.
그 다음에 package.json에 들어가 맨 아래 코드를 추가해주자.
,
"homepage": "https://leeeeeyeon.github.io/yeonmovie_frontend"
그리고 'npm run build' 명령어를 통해 build 폴더를 만들어주었다.
이름은 다르지만, css&js 폴더에 있는 코드들이 우리가 코딩한 코드들이다.
scripts 부분에 들어가 deploy를 추가해주자.
,
"deploy": "gh-pages -d build",
"predeploy": "npm run build"
** build 폴더의 이름과 deploy의 -d 뒤에 이름이 같아야 한다!
predeploy는 deploy 전에 호출되어 build를 한다.
deploy는 gh-pages를 호출하여 build 폴더를 업로드한다.
이제 'npm run deploy'를 하여 배포를 마무리해보자.
https://leeeeeyeon.github.io/yeonmovie_frontend/ 쨔잔~!~!
만약 수정사항이 생기면 'npm run deploy, npm run build'를 하여 업데이트를 해주자.
라우팅
react-router dom을 이용하여 라우팅을 해줄 것이다.
npm install -s react-router-dom
그리고 라우팅을 위해 우리의 디렉토리 구조를 바꿔보자. src 폴더를 아래와 같이 구성하였다.
그리고 App.js의 내용을 Home.js로 옮기고, 웹사이트에 에러가 나지 않게 파일들의 경로를 바꿔주고, index.js에서 App > Home으로 바꾸는 등 세세한 수정을 해주었다.
그리고 App.js에는 함수형 컴포넌트를 만들어 App.js에서 라우팅을 할 것이다.
import React from "react";
import { HashRouter, Route } from "react-router-dom";
import Home from "./routes/Home";
import About from "./routes/About";
function App(){
return(
<HashRouter>
<Route path="/" component={Home}/>
<Route path="/about" component={About}/>
</HashRouter>
);
}
export default App;
- react-router-dom에는 여러 router이 있는데, 그 중 HashRouter을 사용하고 Route도 함께 import 해주었다.
- Router에는 중요한 두 가지 props가 있다. 하나는 어디로 랜더링할지(path), 또 하나는무엇을 랜더링 할지(component)이다.
- import { Home as mySweetHome } 이런 방식으로 이름을 다르게 할 수도 있다는 것을 알아두자.
하지만 ! 이렇게 코드를 짜면 /와 /about이 '/'이 공통되어 /about에 들어갔을 때 두 개의 컴포넌트가 중복되는 문제가 발생한다. 이를 해결하기 위해 exact={true} 속성을 추가하자.
import React from "react";
import { HashRouter, Route } from "react-router-dom";
import Home from "./routes/Home";
import About from "./routes/About";
function App(){
return(
<HashRouter>
<Route path="/" exact={true} component={Home}/>
<Route path="/about" component={About}/>
</HashRouter>
);
}
export default App;
내비게이션
이제 Home과 About에 대한 내비게이션을 만들자.
< App.js >
import React from "react";
import { HashRouter, Route } from "react-router-dom";
import Home from "./routes/Home";
import About from "./routes/About";
import Navigation from './components/Navigation';
function App(){
return(
<HashRouter>
<Navigation />
<Route path="/" exact={true} component={Home}/>
<Route path="/about" component={About}/>
</HashRouter>
);
}
< Navigation.js >
import React from "react";
function Navigation(){
return (
<div>
<a href="/">Home</a>
<a href="/about">About</a>
</div>
);
}
export default Navigation;
하지만 이렇게 하면 링크를 클릭할 때마다 리액트가 죽고, 새로고침이 된다.
이를 해결하기 위해 react-router-dom의 Link를 사용하자.
< Navigation.js >
import React from "react";
import { Link } from "react-router-dom";
function Navigation(){
return (
<div>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</div>
);
}
export default Navigation;
** Link는 Router(우리의 앱에서는 HashRouter) 밖에서 쓸 수 없다 !! Navigation 컴포넌트가 Router 밖에 있으면 안된다.
+ Link가 html로 갈 때 a 태그로 바뀌어 들어가니까 css를 할 때는 a 태그로 진행하면 된다.
+ 니꼬 쌤의 Navigation.css: https://github.com/nomadcoders/movie_app_2019/commit/3ebfa6c16dd4ad07d1d58772cfb0ad08a958ec1e
그리고 라우터를 HashRouter에서 BrowserRouter로 바꾸면 '#'이 붙지 않아 깔끔하다.
하지만 BrowserRouter로 하면 gh-pages 설정이 번거로워진다...
BrowserRouter 사용 시,
나는 BrowserRouter을 택했다.
라우트 간의 props 공유
이번에는 영화 박스를 클릭했을 때, 영화에 대한 상세정보를 띄우도록 할 것이다.
그렇기 위해서는 route 간의 props 공유가 필요하다.
About에 대한 Link 태그를 아래와 같이 수정해보자.
<Link to={{
pathname: "/about",
state: {
fromNavigation: true
}
}}>About</Link>
그리고 About.js을 아래와 같이 수정하면,
import React from "react";
import "./About.css";
function About(props){
console.log(props);
return (
<div className="about__container">
<span>
"Hi"
</span>
<span>- leeeeeyeon, 2021</span>
</div>
);
}
export default About;
state가 전달되는 것을 볼 수 있다.
이를 활용하여 Movie.js를 아래와 같이 바꾸자.
function Movie({year, title, summary, poster, genres}){
return (
<Link to={{
pathname: "/movie-detail",
state: {
year,
title,
summary,
poster,
genres
}
}}>
<div className="movie">
<img src={poster} alt={title} title={title} />
<div className="movie_data">
<h3 className="movie_title">{title}</h3>
<ul className="movie__genres">
{genres.map((genre, index) =>
<li key={index} className="genres_genre">{genre}</li>
)}
</ul>
<h5 className="movie_year">{year}</h5>
<p className="summary">{summary.slice(0, 180)} ...</p>
</div>
</div>
</Link>
);
}
영화 박스를 클릭할 때 해당 영화에 대한 state가 전달되는 것을 볼 수 있다.
리다이렉트
state를 사용하기 위해 Detail.js를 class 컴포넌트로 바꿔주자.
import React from "react";
class Detail extends React.Component{
componentDidMount(){
const {location} = this.props;
}
render(){
return (
<span>Hello</span>
);
}
}
export default Detail;
근데 만약 우리가 영화 박스를 클릭하지 않고 그냥 /movie-detail로 들어갔을 시 undefined 객체가 뜬다.
props 중 history의 push를 이용하여 undefined일 시 (= 링크로 접속) 홈으로 리다이렉트하도록 하자.
import React from "react";
class Detail extends React.Component{
componentDidMount(){
const {location, history} = this.props;
if(location.state === undefined){
history.push("/");
}
}
render(){
return (
<span>Hello</span>
);
}
}
export default Detail;
그리고 movie-detail의 URL을 더 예쁘게 하기 위해
App.js에서는,
<Route path="/movie/:id" component={Detail}/>
Movie.js에서는,
이렇게 바꿔주었다.
그러면 URL이 아래와 같이 바뀐 것을 확인할 수 있다.
노마드 코더 리액트 끗 ~~!~!~