1. 불러올 데이터 추가
포스터, 제목, 장르, 평점, 설명을 json 목록에서 찾아온다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import React, { Component } from "react" import "./App.css" import Movie from "./Movie" //Movie.js에서 여기로 export한 컴포넌트를 import class App extends Component { state = {} // 삭제하면 'movies' property를 읽을 수 없음 componentDidMount() { this._getMovies() } // 함수를 만들어 놓고 _renderMovies = () => { const movies = this.state.movies.map((movie, index) => { // 괄호 넣는 것 잊지 말기 return ( <Movie title={movie.title_english} poster={movie.small_cover_image} key={movie.id} genres={movie.genres} synopsis={movie.synopsis} /> ) //key prop으로 index를 작성 }) return movies } _getMovies = async () => { const movies = await this._callApi() this.setState({ movies }) } _callApi = () => { return ( fetch("https://yts.am/api/v2/list_movies.json?sort_by=download_count?sort_by=rating") // 위의 라인이 완료되면 뭔가를 해라 .then(potato => potato.json()) .then(json => json.data.movies) // 근데 그 라인이 에러가 있으면 catch해서 나한테 보여줘라 .catch(err => console.log(err)) ) } // render에 조건문으로 집어넣기 render() { return ( <div className="App"> {// 데이터가 없다면 'Loading'을 띄우고, 있으면 영화정보가 보이도록 한다. this.state.movies ? this._renderMovies() : "Loading"} </div> ) } } export default App | cs |
골라서 Movie에 추가하고
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster }) { return ( <div> <MoviePoster poster={poster} /> <h1>{title}</h1> </div> ) } function MoviePoster({ poster }) { return <img src={poster} alt="Movie Poster" /> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.array.isRequired, synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
Movies.js에서 propTypes를 추가해준다.
2. html 꾸미기
1 2 3 4 5 6 7 8 9 10 11 12 13 | function Movie({ title, poster }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres" /> </div> </div> ) } | cs |
이제 html를 꾸며줄 차례. 원래 css의 클래스는 class이지만, jsx이므로 className이라고 쓴다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster}) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres" /> </div> </div> ) } function MoviePoster({ poster }) { return <img src={poster} alt="Movie Poster" /> } function MovieGenres({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.array.isRequired, synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired } MovieGenres.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
새로운 functional component를 만들어준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres" /> </div> </div> ) } | cs |
Movie function에도 추가
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } | cs |
Movie__Genres 단락에 출력할 내용을 매핑해준다.
하지만 에러 화면 발생!!! Nicolas가 준 해결책은 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster }) { return <img src={poster} alt="Movie Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
몇몇 movie는 genre가 기재되어 있지 않으므로, propTypes에서 isRequired를 지운다.
하지만 여전히 genres가 undefined 되었다는 에러 발생.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {Movie.genres && Movie.genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster }) { return <img src={poster} alt="Movie Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
Movie component를 rendering 할 때 { Movie.genres && Movie.genres.map(...)}으로 수정해 genres가 존재하면 render 하도록 한다.
장르는 여전히 출력이 안 되는 상태
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster }) { return <img src={poster} alt="Movie Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
코드에서 Movie. 을 지웠더니
드디어 출력됨ㅠㅠㅠㅠ 고마워요 Nicolas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster }) { return <img src={poster} alt="Movie Poster" className="Movie__Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
MoviePoster에서 className까지 지정해서 실행하면,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } | cs |
Movie -> Movie Columns -> Movie poster 구조를 확인할 수 있다.
3. props 추가하고 hover 기능 구현하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} alt={title} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster, alt }) { return <img src={poster} alt={alt} title={alt} className="Movie__Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired, alt: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
MoviePoster에 Props를 하나 더 추가한다.
hover하면 타이틀이 보인다.
정리
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import React, { Component } from "react" import "./App.css" import Movie from "./Movie" //Movie.js에서 여기로 export한 컴포넌트를 import class App extends Component { state = {} // 삭제하면 'movies' property를 읽을 수 없음 componentDidMount() { this._getMovies() } // 함수를 만들어 놓고 _renderMovies = () => { const movies = this.state.movies.map((movie, index) => { console.log(movie) // 괄호 넣는 것 잊지 말기 return ( <Movie title={movie.title_english} poster={movie.medium_cover_image} key={movie.id} genres={movie.genres} synopsis={movie.synopsis} /> ) //key prop으로 index를 작성 }) return movies } _getMovies = async () => { const movies = await this._callApi() this.setState({ movies }) } _callApi = () => { return ( fetch("https://yts.am/api/v2/list_movies.json?sort_by=download_count?sort_by=rating") // 위의 라인이 완료되면 뭔가를 해라 .then(potato => potato.json()) .then(json => json.data.movies) // 근데 그 라인이 에러가 있으면 catch해서 나한테 보여줘라 .catch(err => console.log(err)) ) } // render에 조건문으로 집어넣기 render() { return ( <div className="App"> {// 데이터가 없다면 'Loading'을 띄우고, 있으면 영화정보가 보이도록 한다. this.state.movies ? this._renderMovies() : "Loading"} </div> ) } } export default App | cs |
App 컴포넌트에서 genres와 synopsis의 props를 추가하고
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} alt={title} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster, alt }) { return <img src={poster} alt={alt} title={alt} className="Movie__Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired, alt: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
추가한 props를 여기서 register하고 체크
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} alt={title} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster, alt }) { return <img src={poster} alt={alt} title={alt} className="Movie__Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired, alt: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
그 다음으로, 베이직 html 작업. 클래스명을 JSX로 추가하고 _Movie__Columns -> MoviePoster 만들고, h1 제목 만들고, 장르 array를 매핑하고, Movie__Synopsis 클래스 작성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} alt={title} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster, alt }) { return <img src={poster} alt={alt} title={alt} className="Movie__Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired, alt: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
alt로 이미지의 제목이 뜨도록 함
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import React from "react" import PropTypes from "prop-types" import "./Movie.css" function Movie({ title, poster, genres, synopsis }) { return ( <div className="Movie"> <div className="Movie__Columns"> <MoviePoster poster={poster} alt={title} /> </div> <div className="Movie_Columns"> <h1>{title}</h1> <div className="Movie__Genres"> {genres && genres.map((genre, index) => <MovieGenre genre={genre} key={index} />)} </div> <p className="Movie__Synopsis">{synopsis}</p> </div> </div> ) } function MoviePoster({ poster, alt }) { return <img src={poster} alt={alt} title={alt} className="Movie__Poster" /> } function MovieGenre({ genre }) { return <span className="Movie__Genre">{genre}</span> } // prop의 타입 확인하기 Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired, genres: PropTypes.arrayOf(PropTypes.string), synopsis: PropTypes.string.isRequired } MoviePoster.propTypes = { poster: PropTypes.string.isRequired, alt: PropTypes.string.isRequired } MovieGenre.propTypes = { genre: PropTypes.string.isRequired } export default Movie //App.js로 내보냄 | cs |
genres를 매핑할 때 MovieGenre라는 새로운 functional component를 생성해서 간단한 span을 retrun 하게 함
1 2 3 | <div className="Movie__Genres"> {genres && genres.map((genre, index) => <span className="Movie__Genre" key={index} </span>)} </div> | cs |
이렇게 그냥 span을 안에 집어 넣을 수도 있었지만 더 세련된 코드를 위해 분리한 것. 모든 걸 컴포넌트로 쪼개고, 작게 만드는 것이 더 세련된 코딩이다.
이제 정보들을 예쁜 CSS에 담는 일만 남았다!
'개발새발 개발자 > ReactJS' 카테고리의 다른 글
[ReactJS] 8-1. Building for production (0) | 2018.10.04 |
---|---|
[ReactJS] 7-2. Giving some CSS to Movie (0) | 2018.10.04 |
[ReactJS] 6-3. Async, Await in React (2) | 2018.10.02 |
[ReactJS] 6-2. Promises (0) | 2018.10.01 |
[ReactJS] 6-1. Ajax in React (0) | 2018.10.01 |