만들면서 배우는 리액트 튜토리얼 - 8.어플리케이션 완성(HTML과 CSS 처리)
1.1. HTML 파트
import React, { Component } from 'react';
import './App.css';
import Movie from './Movie'
class App extends Component {
  state = [
  ]
  _renderMovies = () => {
    const movies = this.state.movies.map(movie => {
      return <Movie 
        title={movie.title_english} 
        poster={movie.medium_cover_image} 
        genres={movie.genres} 
        synopsis={movie.synopsis} 
        key={movie.id} 
      />
    })
    return movies
  }
  componentDidMount() {
    this._getMovies();
  }
  _getMovies = async () => {
    const movies = await this._callApi() 
    this.setState({
      movies // ES5 movies: movies
    })
  }
  _callApi = () => {
    return fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating')
    .then(potato => potato.json())
    .then(json => json.data.movies)
    .catch(err => console.log(err))
  }
  render() {
    return (
      <div className="App">
        {this.state.movies ? this._renderMovies() : "Loading..."}
      </div>
    );
  }
}
export default App;
App.js
import React from 'react';
import PropTypes from 'prop-types';
import LinesEllipsis from 'react-lines-ellipsis';
import './Movie.css';
function Movie({title, poster, genres, synopsis}) {
  return (
    <div className="Movie">
      <div className="Movie__Column">
        <MoviePoster poster={poster} alt={title}/>
      </div>
      <div className="Movie__Column">
        <h1>{title}</h1>
        <div className="Movie__Genres">
          {genres.map((genre, index) => <MovieGenre genre={genre} key={index}/>)}
        </div>
        <p className="Movie__Synopsis">
        <LinesEllipsis
          text={synopsis}
          maxLine='3'
          ellipsis=' ...'
          trimRight
          basedOn='letters'
        />
        </p>
      </div>
    </div>
  )
}
function MoviePoster({poster, alt}) {
  return (
    <img src={poster} className="Movie__Poster" alt={alt} title={alt}/>
  )
}
function MovieGenre({genre}) {
  return (
    <span className="Movie__Genre">{genre}</span>
  )
}
Movie.propTypes = {
  title: PropTypes.string.isRequired,
  poster: PropTypes.string.isRequired,
  genres: PropTypes.array.isRequired,
  synopsis: PropTypes.string.isRequired,
}
MoviePoster.propTypes = {
  poster: PropTypes.string.isRequired,
  alt: PropTypes.string.isRequired,
}
MovieGenre.propTypes = {
  genre: PropTypes.string.isRequired,
}
export default Movie;
Movie.js
App.js에서 genre, synopsis 등의 다른 prop들을 추가했다. 
prop이 추가 됐으니 타입 검증을 위한 propType도 추가되었고 
장르는 여러 개일 수 있기 때문에 array로 검증했다.
그리고
해당 prop들을 화면에 출력하기 위해 기본적인 HTML(div, h1, p)과 React 문법
(className 등)을
이용하여 Movie.js에 Movie 함수를 업데이트했다. 
화면은
Movie__Columns라는 이름으로 크게 포스터와 포스터 내용으로 구성했고 
두번째 Movie__Columns 안에 Genre를 나타내는 Movie__Genre, 줄거리를 나타내는 
Movie__Synopsis가 들어가도록 구성했다. 
특히
Genre부분은 더 세련된 코드를 위해 MovieGenre라는 이름의 function 컴포넌트로 
나누고 이를 사용했다.
1.2. CSS파트
.App {
  padding: 50px;
  display: flex;
  justify-content: space-around;
  flex-wrap: wrap;
  height: 100%;
}
.App--loading{
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}
App.css
.Movie{
  background-color: white;
  width: 40%;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  margin-bottom: 50px;
  text-overflow: ellipsis;
  padding: 0 20px;
  box-shadow: 0 8px 38px rgba(133, 133, 133, 0.3), 0 5px 12px rgba(133, 133, 133, 0.22);
}
.Movie__Column{
  width: 30%;
  box-sizing: border-box;
  text-overflow: ellipsis;
}
.Movie__Column:last-child {
  padding: 20px 0;
  width: 60%;
}
.Movie h1{
  font-size: 20px;
  font-weight: 600;
}
.Movie .Movie__Genres{
  display: flex;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.Movie__Genres .Movie__Genre {
  margin-right: 10px;
  color: #B4B5BD;
}
.Movie .Movie__Synpsis {
  text-overflow: ellipsis;
  color: #B4B5BD;
  overflow: hidden;
}
.Movie .Movie__Poster{
  max-width: 100%;
  position: relative;
  top: -20px;
  box-shadow: -10px 19px 38px rgba(83, 83, 83, 0.3), 10px 15px 12px rgba(80, 80, 80, 0.22);
}
@media screen and (min-width:320px) and (max-width:667px) {
    .Movie {
        width:100%;
    }
}
@media screen and (min-width:320px) and (max-width:667px) and (orientation: portrait) {
    .Movie {
        width:100%;
        flex-direction: column;
    }
    .Movie__Poster {
        top: 0;
        left:0;
        width:100%;
    }
    .Movie__Column {
        width: 100% !important;
    }
}
Movie.css
body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  background-color: #EFF3F7;
  height: 100%;
}
html, #root {
  height: 100%;
}
Index.css
|  | 
| [완성된 모습] | 
|  | 
| [포스터를 누르면 사이트로 연결되는 모습] | 

그림의 좌우 라인을 맞출 때 사용하는 justify-content

그림의 위아래 라인을 맞출 때 사용하는 align-items
0 comments