*이 게시글은 Do it! 클론 코딩 영화 평점 웹서비스를 보고 정리한 글입니다.


목차

1. 로딩 구현

2. 영화 API 가져오기

3. 영화 데이터 화면에 그리기

4. 화면 스타일링 하기


1. 로딩 구현

import React from "react";

class App extends React.Component {
  state = {
    isLoading: true,
  };

  render() {
    const { isLoading } = this.state;  //구조분해할당
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>; //삼항연산자
  }
}

export default App;

구조분해할당을 모르면 이해 자체가 안될 것이다

구조 분해 할당 - JavaScript | MDN (mozilla.org)

 

위 설명을 잘 참고하길 바란다.

 

state 내부의 isLoading을 개별 변수로 사용하기 위해 구조분해할당 기법을 사용하였다. 

구조분해할당한 덕분에 isLoading을 변수로 쓸 수 있게 되었다.

 

삼항연산자는

isLoading이 True면 Loading이 출력되고 False면 We are ready가 출력된다.

 

영화를 담아야하니 state에 movies라는 배열도 추가한다

import React from "react";

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

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

2. 영화 API 가져오기

우선 render()함수가 실행되면 호출되는 생명주기 함수가 바로 componentDidMount()함수이다.

이 함수를 이용해서 렌더링된 후 바로 화면에 나와야할 영화데이터를 넣을 것이다.

 

원래는 자바스크립트의 fetch() 함수를 알아야하지만 초보자가 사용하기는 난이도가 있어서 Axios라는 도구를 사용한다.

npm install axios

API Documentation - YTS YIFY

영화 데이터를 위 사이트에서 가져올 것이다

 

아래와 같이 App.js 파일을 수정한다.

화면에는 Loading...만 나오지만 오류가 나오지 않으므로 axios는 잘 작동하는 것이다.

import React from "react";
import axios from 'axios';

class App extends React.Component {
  state = {
    isLoading: true,
    movies: [],
  };
  componentDidMount(){
    axios.get('https://yts-proxy.now.sh/list_movies.json');
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

브라우저에 F12를 눌러서 나오는 관리자모드에 네트워크에 들어가면

list_movies.json이라는 것이 보이는데 이게 axios가 API를 호출하고 있기 때문에 생긴 것이다

 

axios는 네트워크를 사용하기 때문에 느리게 작동한다.

그래서 axios.get()이 반환한 영화 데이터를 잡으려면 자바스크립트에서 axios.get()을 포함하고 있는 함수의 실행이 끝날 때 까지 시간이 걸릴 수 있다고 알려줘야한다.

 

getMovies라는 함수를 만들고 그 함수 안에서 axios.get()이 실행되도록 만든다.

그리고 axios.get()이 반환한 결과를 movies에 저장한다.

import React from "react";
import axios from 'axios';

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

  getMovies=()=>{
    const movies =axios.get('https://yts-proxy.now.sh/list_movies.json');
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

 

이렇게 하면 componentDidMount()함수가 실행되면 this.getMovies()가 실행될 것이다.

이때 자바스크립트에게 getMovies()함수는 시간이 좀 필요하다고 말해야만

axios.get()이 반환한 데이터를 제대로 잡을 수 있다.

그것을 하기 위해서 async, await라는 키워드가 필요하다.

 

자바스크립트에게 getMovies()함수는 시간이 필요하다고 알리기위해 async를 쓰고

axios.get()의 실행을 기다려 달라고 말해주기 위해 await가 필요하다

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const movies =await axios.get('https://yts-proxy.now.sh/list_movies.json');
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

 

중간정리

리액트 앱이 실행되면 최초로 render()함수가 실행되고 최초의 state에는 isLoading, movies가 있다.

isLoading은 true이고 movies는 빈배열이다

 

이어서 App 컴포넌트가 마운트되면 componentDidMount() 함수가 실행되면서 getMovies() 함수가 실행된다.

여기서 getMovies()함수에 시간이 많이 걸리는 axios.get()이 포함돼있어 async와 awawit를 붙여준다.


3. 영화 데이터 화면에 그리기

 

console.log(movies)라고 해보자.

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const movies =await axios.get('https://yts-proxy.now.sh/list_movies.json');
    console.log(movies);
    
  }

  componentDidMount(){
    this.getMovies();
    
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

콘솔에 보면 우리가 영화 사이트를 만들기 위해 필요한 정보들이 들어있다.

data->data->movies 순서대로 개갸체에 접근하면 원하는 데이터를 추출할 수 있을 것이다

 

console.log(movies.data.data.movies)라고 해보자.

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const movies =await axios.get('https://yts-proxy.now.sh/list_movies.json');
    console.log(movies.data.data.movies);
    
  }

  componentDidMount(){
    this.getMovies();
    
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

 

원하는대로 원하는 영화 데이터만 추출할 수 있게 된 것이다

movies.data.data.movies로 객체에 접근하는 것은 아름답지않아서 아래와같이 구조분해할당으로 코드를 수정한다.

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const {data:{
      data:{
        movies
      }
    }} =await axios.get('https://yts-proxy.now.sh/list_movies.json');
    console.log(movies);
    
  }

  componentDidMount(){
    this.getMovies();
    
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

똑같은 결과인 것을 볼 수 있다.

 

데이터 추출을 했으니 이제 이 영화 데이터를 state에 저장하면 될 것이다.

console.log를 지우고 this.setState({movies:movies});를 입력한다.

 

setState는 State 값을 변경해준다.

빈 배열이던 movies state에 movies(영화 데이터)를 넣어준다.

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const {data:{
      data:{
        movies
      }
    }} =await axios.get('https://yts-proxy.now.sh/list_movies.json');
    this.setState({movies:movies});
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

그런데 자바스크립트 ES6에서는 객체의 키와 대입할 변수의 이름이 같다면 코드를 축약할 수 있다.

this.setState({movies:movies});를

this.setState({movies})로 쓸 수 있는 것이다

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const {data:{
      data:{
        movies
      }
    }} =await axios.get('https://yts-proxy.now.sh/list_movies.json');
    this.setState({movies});
  }

  componentDidMount(){
    this.getMovies();
    
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

 

영화데이터를 받았으니 Loading화면이 아니라 We are ready가 출력돼야할 것이다.

따라서 setState에 isLoading을 false로 바꾸는 내용을 추가한다.

 this.setState({movies, isLoading: false});

import React from "react";
import axios from 'axios';

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

  getMovies=async ()=>{
    const {data:{
      data:{
        movies
      }
    }} =await axios.get('https://yts-proxy.now.sh/list_movies.json');
    this.setState({movies, isLoading: false});
    
  }



  componentDidMount(){
    this.getMovies();
    
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

 

영화데이터를 받았고 영화데이터를 받은 후 isLoading, Movies state값을 변경해줬지만 화면에는 영화 데이터가 아닌 We are ready만 뜬다.

우리는 We are ready가 아니라 영화 정보가 렌더링돼야 하므로 movies state를 그리기 위해 Movies 컴포넌트를 만든다.

 

Movie.js라는 파일을 만든다.

Movie 컴포넌트는 state가 필요하지 않으므로 함수형 컴포넌트로 만든다.

 

아래와 같이 뼈대를 만든다.

import React from 'react';
import PropTypes from 'prop-types';

function Movie(){
 return <h1></h1>;
}


Movie.propTypes = {};

export default Movie;

 

위 링크에서 필요한 데이터가 뭔지 일단 확인한다.

아래와 같이 안뜨면 크롬브라우저 스토어에서 JSON 뷰어를 설치하기 바란다.

필요한 데이터를 확인하고

개발자가 실수하는 것을 방지하기 위해 우선 propTypes를 작성한다.

주의할 것은 poster에는 image의 주소가 들어간다

API에서는 medium_cover_image라고 했지만 이해하기 쉽도록 poster라고 지정했다.

import React from 'react';
import PropTypes from 'prop-types';


function Movie() {
  return (
    <div>
    
    </div>
  );
}

Movie.propTypes = {
  id : PropTypes.number.isRequired,
  year: PropTypes.number.isRequired,
  title: PropTypes.string.isRequired,
  summary: PropTypes.string.isRequired,
  poster: PropTypes.string.isRequired,
};

export default Movie;

그냥 영화를 보여주면 재미없으므로 랭킹 순서대로 보여주기 위해 axios.get()에 주소를 수정한다.

await axios.get('https://yts-proxy.now.sh/list_movies.json?sort_by=rating');
import React from "react";
import axios from 'axios';

class App 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});
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading } = this.state;
    return <div>{isLoading ? "Loading..." : "We are ready"}</div>;
  }
}

export default App;

 

이제 평점 내림차순으로 영화 데이터를 가져올 수 있게 되었으므로 App 컴포넌트에서 Movie 컴포넌트로 id, title, year, summary ,poster props를 넘겨주면 된다. 

 

아래와 같이 구조 분해 할당으로 props를 받는다.

import React from 'react';
import PropTypes from 'prop-types';


function Movie({ id,title, year, summary, poster }) {
  return (
    <div >
      <img src={poster} alt={title} title={title} />
      <div >
        <h3 >{title}</h3>
        <h5 >{year}</h5>
        <p >{summary}</p>
      </div>
    </div>
  );
}

Movie.propTypes = {
  id : PropTypes.number.isRequired,
  year: PropTypes.number.isRequired,
  title: PropTypes.string.isRequired,
  summary: PropTypes.string.isRequired,
  poster: PropTypes.string.isRequired,
};

export default Movie;

 

그 후 App.js(App 컴포넌트)로 가서 영화 데이터에 props를 전달할 수 있도록 수정한다.

 

제일 먼저 Movie component import(가져오기)를 한다.

import Movie from'./Movie';

 

그다음 We are ready를 지우고 movies.map()으로 변경한다.

movie라는 변수에 movies 배열의 요소 하나하나를 다 저장하고 콘솔화면에 그 변수를 출력하는 코드로 수정한다.

그 후 Movie 컴포넌트를 리턴한다.

Movie 컴포넌트를 리턴하긴 했지만 props를 전달하지 않아 아무것도 출력되지 않는다.

return <div>{isLoading ? "Loading..." : movies.map(
      (movie)=>{
        console.log(movie);
        return <Movie />;
    }
import React from "react";
import axios from 'axios';
import Movie from'./Movie';

class App 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});
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading, movies } = this.state;
    return <div>{isLoading ? "Loading..." : movies.map(
      (movie)=>{
        console.log(movie);
        return <Movie />;
    }
    )}</div>;
  }
}

export default App;

 

Movie 컴포넌트에 props를 전달한다.

   return <Movie 
        id={movie.id}
        year={movie.year}
        title={movie.title}
        summary={movie.summary}
        poster={movie.medium_cover_image}

        
        />;
import React from "react";
import axios from 'axios';
import Movie from'./Movie';

class App 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});
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading, movies } = this.state;
    return <div>{isLoading ? "Loading..." : movies.map(
      (movie)=>{
        console.log(movie);
        return <Movie 
        id={movie.id}
        year={movie.year}
        title={movie.title}
        summary={movie.summary}
        poster={movie.medium_cover_image}

        
        />;
    }
    )}</div>;
  }
}

export default App;

 아래와 같이 화면에 잘 뜨는 것을 볼 수 있다.

 

마지막으로

 

App 컴포넌트에 

console.log(movie)는 필요없으니 지우고 key 값을 추가한다.

 

아래와 같이 컴포넌트를 여러개 출력할 때는 유일한 값을 이용하여 key props를 추가해야한다.

   return <div>{isLoading ? "Loading..." : movies.map(
      (movie)=>{
        return <Movie 
        key={movie.id} //이 부분
        id={movie.id}
        year={movie.year}
        title={movie.title}
        summary={movie.summary}
        poster={movie.medium_cover_image}
        />;
    }
    )}</div>;

 

import React from "react";
import axios from 'axios';
import Movie from'./Movie';

class App 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});
  }

  componentDidMount(){
    this.getMovies();
  }

  render() {
    const { isLoading, movies } = this.state;
    return <div>{isLoading ? "Loading..." : movies.map(
      (movie)=>{
        return <Movie 
        key={movie.id}
        id={movie.id}
        year={movie.year}
        title={movie.title}
        summary={movie.summary}
        poster={movie.medium_cover_image}
        />;
    }
    )}</div>;
  }
}

export default App;

출처

Do it! 클론 코딩 영화 평점 웹서비스-니꼴라스

 

+ Recent posts