[React] Movie-app 제작

추천 영화 List로부터 영화를 소개시켜주는 movie app

기본 설정

  • node.js
  • prop-types
    전달받은 props가 예상한 props인지 확인하기
$ npm i prop-types
import PropTypes from 'prop-types'
  • axios
    node.js와 브라우저를 위한 HTTP통신 라이브러리.data fetch
$ npm i axios
import axios from 'axios';
  • react-router-dom
    Router를 이용해 스크린간 이동
$ npm install react-router-dom
import { HashRouter , Route} from "react-router-dom";
  • npx create-react-app
  • VS Code사용

Application이 빈 html을 로드하고 react가 html을 밀어넣음으로써 소스코드에는 존재하지 않는 VirtualDOM을 만들어 속도가 빠른 React의 장점 활용

App.js

  • 네비게이션을 만들어 주는 패키지 react-router-dom
  • react-router-dom속 많은 router 패키지 중 hashrouter, route를 import

Route

  • 요청받은 pathname에 해당하는 component를 렌더링
  • <Route>에는 렌더링할 스크린(path)과 뭘 할지(component)정해주는 2개의 props가 존재
    둘의 이름이 같아야 하진 않지만 편의를 위해 보통 일치
  • react router는 url을 먼저 가져온 후 비교 하기에 2개의 component가 동시에 render되는 것을 방지하기위해 exact={true}를 설정
  • BrowserRouter(#을 포함X)도 있지만 github pages에 정확히 설정하기 까다롭기에 HashRouter사용
import { HashRouter , Route} from "react-router-dom";

function App(){
  return (
  <HashRouter>
    <Navigation/>
    <Route path="/" exact={true} component={Home} />
    <Route path="/about" component={About} />
    <Route path="/movie/:id" component={Detail} />
  </HashRouter>
  )
}

export default App;
  • Home, about 2개의 스크린이 필요

Router

  • 기존 html사용 시 a태그 href를 사용해 스크린을 이동하면 react는 죽고 새 페이지가 새로고침이 되기에 Link태그 to를 이용
  • Router안에 있는 모든 Route들은 props를 가지는데 이를 사용할 수 있음

    react-router 공식문서에 따르면 to=} 등으로 변경할 수도있음

  • router밖에서 Link를 사용하는 것은 불가능
import {Link} from "react-router-dom";

function Navigation(){
  return (
  <div className="nav">
    <Link to="/">Home</Link>
    <Link to="/about">About</Link>
  </div>
  )
}

export default Navigation;

Home.js

  • YTSsite movie-list API를 가져오기 위해 axios를 활용
  • 다소 시간이 소비되는 axios를 가진 conponentDidMount가 완료될 때 까지 기다리린 후 실행을 위한 async-await(thanks to ES6)
  • 이에 isLoading값이 false로 변환되면 movies배열에 전달된 object에서 필요한 영화 정보만을 가지고 Movies.js를 호출
import React from 'react';
import axios from 'axios';

class  Home extends React.Component {
  state = {
    isLoading: true,
    movies : []
  };

  getMovies = async() => {
    const {
      data: {
        data: { movies }
      }
    } = await axios.get("https://yts-proxy.now.sh/list_movies.json?sort_by=rating")
    this.setState({ movies, isLoading: false})
  }
    //movies배열에 영화 list넣은 후 loading 완료 -> wer'e ready
    //this.setState({ movies : movies})  setState의 movies : axios의 movies
  
  componentDidMount() {
    this.getMovies()
  }
  
  render(){  //react는 자동적으로 render실행
    const {isLoading, movies} = this.state
    return (
      <section className="container">
      { isLoading ? (
      <div className="loader"><span className="loader__text">Loading...</span> </div> 
      ) : (
      <div className="movies">
        {movies.map(movie =>(
            <Movie
              key={movie.id}
              id={movie.id}
              year={movie.year}
              title={movie.title}
              summary={movie.summary}
              poster={movie.medium_cover_image}
              genres={movie.genres}
            />
        ))}
      </div>
      )}
  </section>)
  }
}

export default Home;

Movie.js

  • Movie의 모든 props를 Link의 object로 사용하기 위해 props-type을 통한 error check
  • 자바스크립트 문법을 이용해 year : year, title : title처럼 복잡하게 선언하지 않음
  • item과 index 2가지 argument를 전달하는 map함수를 이용해 key값이 없는 오류를 해결
import React from 'react';
import PropTypes from 'prop-types'
import {Link} from "react-router-dom";

function Movie({id, year, poster, summary, title, genres}){
  return (
    <div className="movie">
      <Link to=
      {
        {
          pathname: `/movie/${id}`,
          state:
          {
            year,
            title,
            summary,
            poster,
            genres
          }
        }
      }
      >
      <img src={poster} alt={title} title={title} />
      <div className="movie__data">
        <h3 className="movie__title"> {title} </h3>
        <h5 className="movie__year">{year}</h5>
        <ul className="movie__genres">
          {genres.map((genre, index) => (
            <li key={index} className="genres__genre">{genre}</li>
          ))}
        </ul>
        <p className="movie__summary">{summary.slice(0, 140)}...</p>
      </div>
    </Link>
    </div>
  )
}

Movie.propTypes = {
  id : PropTypes.number.isRequired,
  year : PropTypes.number.isRequired,
  poster : PropTypes.string.isRequired,
  summary : PropTypes.string.isRequired,
  title : PropTypes.string.isRequired,
  genres : PropTypes.arrayOf(PropTypes.string).isRequired
}

export default Movie;

Detail

  • 리스트의 영화 카드를 선택하지 않고 url을 직접 https://dtwogud.github.io/movie-app-2021/#/movie/15553와 같이 지정해 들어올 경우 object전달이 불가능하기에 Home으로 redirect
  • 전달된 object중 웹사이트가 어디있는지 장소를 바꿀 수 있는 history를 사용
import React from 'react';

class Detail extends React.Component {

  componentDidMount() {
    const {location, history} = this.props;
    if (location.state === undefined) {
      history.push("/");
    }
    console.log(location.state);
  }

  render() {
    const {location, history} = this.props;
    if (location.state){
      return (
        <div>
      <span>{location.state.title}</span><br></br>
      <span>{location.state.summary}</span>
      </div>
        )
    }
    else {
      return null;
    }
  }
}

export default Detail;

댓글남기기