만들면서 배우는 리액트 튜토리얼 - 8.어플리케이션 완성(HTML과 CSS 처리)

by - September 02, 2018

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


You May Also Like

0 comments