[React] ReactJS로 영화 웹 서비스 만들기 (7) 完
Lpla
·2021. 2. 20. 22:16
반응형
- 이번 시간에는 라우터의 기본 기능을 익히며 리액트 기초 강의를 마무리하도록 하겠다.
라우터 설치 및 준비
- 라우터는 한 페이지 내에서 명령에 따라 필요한 컴포넌트를 불러오는 형태를 말한다.
- 우리는 2개의 라우터를 만들 것이다.
- 이전 시간까지 만든 영화 페이지를 Home 탭에, 사이트를 소개하는 내용을 About 탭에 만드는 것이 목적이다.
npm i react-router-dom
으로 라우터를 설치한다.- 그리고 src폴더 안에 components, routes 라는 이름으로 2개의 새 폴더를 만든다.
- components 폴더 안에 Movie.css와 Movie.js를 옮긴다.
- 그리고 routes 폴더 안에 About.js와 Home.js를 만든다.
- 이제 App.js와 App.css 를 Home.js와 Home.css 로 바꾼다. App.js 의 코드를 모두 복사하여 Home.js 에 붙여 넣는다.
- App.css 의 코드는 비어 있을 것이다. 일단 이름만 Home.css로 바꿔준다.
- 경로와 이름이 달라졌으니 App.js 상단에
import Movie from "./Movie"
를import Movie from "../components/Movie"
로 수정하고 바로 아래 css도import "./Home.css"
도 바꿔준다. class App extends React.Component
도class Home extends React.Component
로 바꾼다.- App.js 의 기존 코드를 모두 지우고 처음부터 작성한다.
App.js
import React from "react";
function App() {
return <span>없음</span>
}
export default App;
- 에러 없이 화면이 보인다면 파일을 무사히 옮긴 것이다.
라우터로 네비게이션 만들기
- 이제 App.js에 라우터를 만든다.
App.js
import React from "react";
import { HashRouter, Route } from "react-router-dom";
import About from "./routes/About";
function App() {
return (
<HashRouter>
<Route path="/about" component={About} />
</HashRouter>
)
}
export default App;
- HashRouter를 import 한다.
- 이 HashRouter를 사용하여 url에 해시(#)을 붙일 수 있고 서버에 요청 없이 화면을 보여줄 수 있다.
- url에 해시가 붙는 것이 싫다면 HashRouter 대신에 BrowserRouter 를 사용하면 된다.
- (실제로 BrowerRouter 사용률이 훨씬 높다. 다만 우리가 자료를 배포하고 있는 gh-pages에는 BrowserRouter를 사용하면 에러가 발생한다고 하니 HashRouter를 사용하겠다.)
- 그리고 비어 있는 About.js에 컴포넌트를 하나 생성한다.
About.js
import React from "react";
function About() {
return (
<div>
<p>About페이지입니다.</p>
<p>영화 웹서비스 만들기 공부 중입니다.</p>
</div>
)
}
export default About;
- /about 으로 접속하면 입력한 내용을 확인할 수 있다.
- Home도 똑같은 방식으로 생성하면 되는데 일단 아래와 똑같이 만들어보자.
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;
- 기본 경로(/)에 Home 컴포넌트를 연결했고, /about에 About 컴포넌트를 연결했다.
- 이제 기본 페이지를 확인하면 영화 리스트가 잘 보인다.
- 여기까지는 문제 없다.
- 하지만 /about 주소로 이동하면 about만 단독으로 있지 않고 Home도 함께 보인다.
- 조금만 생각하면 상위 컴포넌트까지 렌더링한 것을 알 수 있다.
- 이것이 리액트 라우터가 작동하는 방식이다.
- 헤결 방법은
<Route path="/" exact={true} component={Home} />
처럼 exact를 추가하면 된다.
- 이제 각각의 페이지를 구분 지었으니 네비게이션을 만들면 된다.
- App.js 상단에 Navigation을 import하고 HashRouter 안에 네비게이션 컴포넌트를 불러온다.
import Navigation from "./components/Navigation";
function App() {
return (
<HashRouter>
<Navigation />
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
</HashRouter>
)
}
- components 폴더 안에 Navigation.js 를 만들고 컴포넌트를 생성한다.
import React from "react";
function Navigation() {
return (
<div className="nav_con">
<a href="/">Home</a>
<a href="/about">About</a>
</div>
)
}
export default Navigation;
- css로 중앙정렬만 맞추고 페이지를 새로고침하면 네비게이션이 정상적으로 보이지만 한 가지 문제가 있다.
- 우리는 네비게이션에 a태그를 사용했기 때문에 Home이나 About을 클릭하게 되면 페이지가 새로고침된다.
- 새로고침 없이 페이지를 이동하길 원하기 때문에 이를 없애야 한다.
- 먼저 App.js 상단에
import { HashRouter, Route } from "react-router-dom";
을 import 한다. - 그리고
<a href="/">
대신에<Link to="/">
로 두 태그를 바꾼다. - 이제 다시 시도해보면 새로고침 없이 페이지가 바뀐다.
- 다만 Link는 라우터 안에 있어야 한다.
영화 정보 가져가기
- 이제 영화 리스트에서 영화를 하나 클릭했을 때 그 영화의 세부 정보가 담긴 페이지로 이동하려고 한다.
- 그전에 route props 를 알아야 한다. About.js 를 열어보자.
- 모든 컴포넌트는 props를 가진다. About 컴포넌트에 props를 추가하고 console.log(props); 를 추가해보자.
import React from "react";
import "./About.css";
function About(props) {
console.log(props);
return (
<div className="about_con">
<p>About페이지입니다.</p>
<p>영화 웹서비스 만들기 공부 중입니다.</p>
</div>
)
}
export default About;
- history, location, match, staticContext 총 네 개의 props가 존재하고 있다.
- 이것은 react-router에 의해 만들어진 것으로 이 props의 정보를 다른 곳에 전달할 수 있다.
- 이제 props를 about에 보내는 작업을 해보자.
- Navigation.js 의 Link to는 문자열(string)이나 객체(object)로 대체할 수 있다.
function Navigation() {
return (
<div className="nav_con">
<Link to="/">Home</Link>
<Link to={{
pathname:"/about",
state: {
fromNavigation: true
}
}}>About</Link>
</div>
)
}
- Link에 기존의 /about 대신 pathname과 state를 입력하고 다시 about 페이지로 이동해봤다.
- 그러자 pathname과 state가 about페이지에도 따라 오는 것을 확인할 수 있었다.
- 이 과정은 props를 다른 곳에 전달할 수 있다는 것을 확인하기 위함이었으니 다시 Navigation.js를 원래대로 돌리고 영화 정보를 전달하기 위한 새로운 컴포넌트를 만든다.
Movie.js
import { Link } from "react-router-dom";
function Movie({ id, year, title, summary, poster, genres }) {
return (
<Link to={{
pathname: "/movie-detail",
state: {
year:year,
title:title,
summary:summary,
poster:poster,
genres:genres
}
}}>
<div className="movie_list">
<div className="movie_poster">
<img src={poster} alt={title} />
</div>
<div className="movie_contents">
<h3 className="movie_title">{title}</h3>
<h5 className="movie_year">{year}</h5>
<ul className="movie_genres">
{genres.map((genres, index) => (
<li key={index} className="genres_list">
{" "}
{genres}{" "}
</li>
))}
</ul>
<p className="movie_summary">{Component(summary)}</p>
</div>
</div>
</Link>
);
}
- Movie.js에도 Link 를 만들기 위해 상단에 Link 를 import 하고 movie_list 클래스를 Link로 감싼다.
- state에 영화의 모든 정보를 담는다. movie_list 바깥에 a태그를 추가했기 때문에 레이아웃이 깨졌을 것이다.
Movie.css
.movies_container > a { margin-bottom: 10rem; display: flex; flex-basis: 48%; background: #fff; box-shadow: 4px 4px 14px 0px #cacaca; }
.movie_list { display: flex; }
- 각자 맞게 css를 다시 맞추고 routes 폴더에 Detail.js 를 추가한다.
- 우선 잘 동작하는지 확인하기 위해 컴포넌트를 간단하게 만든다.
Detail.js
import React from "react";
function Detail(props) {
console.log(props);
return <span>테스트</span>
}
export default Detail;
- 마지막으로 App.js 에 detail.js 를 불러온다.
import Detail from "./routes/Detail";
function App() {
return (
<HashRouter>
<Navigation />
<Route path="/" exact={true} component={Home} />
<Route path="/about" component={About} />
<Route path="/movie-detail" component={Detail} />
</HashRouter>
)
}
export default App;
- 이제 영화를 하나 클릭하면 테스트라는 글자가 보이고 콘솔을 확인하면 영화의 정보를 가져온 것을 알 수 있다.
- 훌륭하다!
리다이렉트
- 우리는 링크를 통해 영화 정보를 라우터로 보내는데 성공했다.
- 그 말은 즉 영화를 클릭해야 영화 정보가 전송된다. 그렇지 않고 단순히 /movie-detail 를 직접 입력해서 들어오면 아래처럼 state에 undefined가 찍힌다.
- 우리는 if문으로 state가 undefined일 때 사용자들을 영화 리스트 페이지로 강제 이동시킬 수 있다.
- 먼저 Detail.js 에 작성한 내용을 클래스 컴포넌트로 바꿔야 한다.
- 클래스 컴포넌트로 바꾸는 이유는 생명주기(Life Cycle)로 컴포넌트 실행 순서를 조작하기 위함이다.
Detail.js
import React from "react";
class Detail extends React.Component {
componentDidMount() {
const { location } = this.props;
console.log(location.state);
}
render() {
return <span>테스트</span>
}
}
export default Detail;
- 다시 /movie-detail 페이지에서 새로고침하면 콘솔에 undefined가 찍힌다.
- 자 그럼 console.log 대신에 조건문으로 홈 디렉토리로 리다이렉트시키면 끝이다.
- 페이지를 강제이동 시키는 방법에는 history.push() 가 있다.
const { location, history } = this.props;
console.log(history);
- componentDidMount에 console.log(history); 를 추가하고 확인해보자.
- go, goBack, goForward 등 여러가지가 존재하는데 이것들이 url을 변경하는데 사용된다.
- 그 중에서 가장 많이 사용하는 방법이 push이다.
componentDidMount() {
const { location, history } = this.props;
if (location.state === undefined) {
history.push("/");
}
}
- 조건문을 완성하면 영화를 클릭했을 때, /movie-detail 에 접속할 수 있고 그렇지 않다면 홈으로 리다이렉트된다.
- 이것으로 리다이렉트는 완성했다.
영화 정보 입력하기
- 이제 조건을 만족하면 영화 정보를 html에 쓰는 작업만 남았다.
- 지금까지 배운 것을 바탕으로 생각하면 금방 할 수 있을 것이다.
import React from "react";
class Detail extends React.Component {
componentDidMount() {
const { location, history } = this.props;
if (location.state === undefined) {
history.push("/");
}
}
render() {
const { location } = this.props;
return (
<div className="movie_detail">
<span>{location.state.year}</span>
<span>{location.state.title}</span>
<span>{location.state.summary}</span>
<span>{location.state.poster}</span>
<span>{location.state.geners}</span>
</div>
)
}
}
export default Detail;
- 이제 영화를 클릭하면 영화 정보가 보인다.
- 하지만 그 상태에서 다시 /movie-detail 로 이동하면 에러가 발생한다.
- year 즉 영화 정보를 찾을 수 없기 때문에 발생하는 오류이다.
- render에도 조건문을 추가해야 한다.
render() {
const { location } = this.props;
console.log(location.state);
if (location.state){
return (
<div className="movie_detail">
<span>{location.state.year}</span>
<span>{location.state.title}</span>
<span>{location.state.summary}</span>
<span>{location.state.poster}</span>
<span>{location.state.geners}</span>
</div>
)
} else {
return null;
}
}
영화마다 다른 url 이동하기
- 지금은 영화를 클릭하면 어떤 영화든지 /movie-detail 로 이동한다.
- 만약 고유한 url을 갖게 하고 싶다면 어렵지 않다. Movie.js 에서 pathname을 수정한다.
function Movie({ id, year, title, summary, poster, genres }) {
return (
<Link to={{
state: {
pathname: `movie/${title}`,
}
}}>
)
}
- 나는 /movie/"영화제목" 으로 만들었다.
- 그리고 App.js 에서 라우터를 수정해준다.
<HashRouter>
<Route path="/movie/" component={Detail} />
</HashRouter>
- 각각의 고유한 url이 확인된다.
총평
- 이 수업으로 베일에 감춰진 리액트를 흐릿하게나마 알 수 있었다.
- 하지만 아직까지는 리액트가 여전히 낯설고 코드도 쉽게 떠오르지 않는다.
- 리액트 입문은 이것으로 마치고 여름이 찾아올 때 쯤 국내 기초~중급 강의를 들으면서 실무에 대한 감각을 익혀야겠다.
반응형