본문 바로가기

개발새발 개발자/ReactJS

[ReactJS] 7-1. Updating Movie Component

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