[1] API에서 데이터 가져오기 (fetch)
- fetch를 하기 위해 axios를 설치한다.
- 참고: https://www.npmjs.com/package/axios
- 설치: npm i axios (i는 install의 약자)
- YTS에서 API를 사용하기로 결정
- https://yts.mx/api
첫번째 Endpoint를 확인해보면 이와같이 json으로 된 데이터들을 확인할 수 있다.
하지만 이 url을 사용하면 url이 계속 바뀌기 때문에 프로그램을 만들어도 항상 에러가 생긴다!
그래서 노마드 코드에서 제공하는 url을 사용하기로 한다. (https://github.com/serranoarevalo/yts-proxy)
-> https://yts-proxy.now.sh/list_movies.json
import React from 'react';
import axios from 'axios';
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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;
하지만 이렇게 하면 api에서 데이터를 사용하지 않고 있기 때문에 에러가 남 -> 변수에 담음
import React from 'react';
import axios from 'axios';
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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;
하지만 movies변수에 담았지만, 이때 데이터를 가져오는데 시간이 조금 걸릴 수 있다. 그렇기 때문에 데이터를 가져올 때까지 기다려야함 => await를 이용 => await를 쓰려면 그 함수가 async해야하므로 async함수로 만듦
[2] movie 데이터 출력 (rendering)
getMovies = async() => {
const movies = await axios.get("https://yts-proxy.now.sh/list_movies.json");
console.log(movies);
}
movies를 출력해보면 다음과 같다
우리가 원하는 데이터는 object>data>data>movies 이다.
즉, console.log(movies.data.data.movies); 를 하면 우리가 원하는 movies 데이터만 콘솔창에 출력된다.
하지만 이렇게 표현하면 movies변수에 movies 데이터만 담을 수 있다.
getMovies = async () => {
const { data: { data: { movies } } } = await axios.get("https://yts-proxy.now.sh/list_movies.json");
console.log(movies);
}
그리고 이 변수를 state movie변수에 지정해주어야 하는데
this.setState({movies: movies}) // 원래는 이렇게 해야하지만
this.setState({movies}) // 리액트는 똑똑해서 이렇게 해도 알아듣는다
// App.js
import React from 'react';
import axios from 'axios';
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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;
movies 데이터를 가져왔으면 isLoading 변수도 false로 바꿔준다.
이 때, 두개의 state를 바꾸지만 한번의 setState만 사용하면 된다.
- Movie.js 파일 생성
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});
}
따라서 url에 sort_by를 추가해주었다. (App.js 파일)
// App.js
import React from "react";
import axios from "axios";
import Movie from "./Movie";
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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 => (
<Movie
key = {movie.id}
id = {movie.id}
year = {movie.year}
title = {movie.title}
summary = {movie.summary}
poster = {movie.medium_cover_image}
/>
))}</div>;
/*
movies.map(movie => {
return <Movie />
})
와
movies.map(movie => (
<Movie /<
))
와 같음
*/
}
}
export default App;
이때, key값을 지정하지 않으면 다음과 같은 에러가 뜬다.
// Movie.js
import React from "react";
import PropTypes from "prop-types";
function Movie({id, year, title, summary, poster}){
return <h4>{title}</h4>;
}
Movie.propTypes = {
id: PropTypes.number.isRequired,
year: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
poster: PropTypes.string.isRequired //medium_cover_image
}
export default Movie;
[결과]
[3] Styling the Movies
// App.js
import React from "react";
import axios from "axios";
import Movie from "./Movie";
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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 (<section class="container">
{isLoading ? (
<div class="loader">
<span class="loader_text">Loading...</span>
</div>
) : (
<div class="movies">
{movies.map(movie => (
<Movie
key={movie.id}
id={movie.id}
year={movie.year}
title={movie.title}
summary={movie.summary}
poster={movie.medium_cover_image}
/>
))}
</div>
)}
</section>);
}
}
export default App;
// Movie.js
import React from "react";
import PropTypes from "prop-types";
import "./Movie.css"; // 스타일 추가
function Movie({year, title, summary, poster}){
return (
<div class="movie">
<img src={poster} alt={title} title={title} />
<div class="movie__data">
<h3 class="movie__title">{title}</h3>
<h5 class="movie__year">{year}</h5>
<p class="movie__summary">{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 //medium_cover_image
}
export default Movie;
css파일을 추가해서 디자인 할 수 있다.
body {
background-color: #f2f2f2;
}
-> Movie.css 파일
[결과]
[Error Fix]
위 에러가 나는 이유는 class안에서 html의 class속성을 지정했기 때문에 자바스크립트가 혼동이 왔기 때문이다.
따라서 모든 class를 className으로 바꿔주어야 한다. 비슷한에로 <label>태그의 for도 htmlFor이라고 써야한다.
import React from "react";
import axios from "axios";
import Movie from "./Movie";
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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 (<section className="container">
{isLoading ? (
<div className="loader">
<span className="loader_text">Loading...</span>
</div>
) : (
<div className="movies">
{movies.map(movie => (
<Movie
key={movie.id}
id={movie.id}
year={movie.year}
title={movie.title}
summary={movie.summary}
poster={movie.medium_cover_image}
genres={movie.genres}
/>
))}
</div>
)}
</section>);
}
}
export default App;
이렇게
[4] genre 추가
[Movie.js]
import React from "react";
import PropTypes from "prop-types";
import "./Movie.css";
function Movie({year, title, summary, poster, genres}){
return (
<div className="movie">
<img src={poster} alt={title} title={title} />
<div className="movie__data">
<h3 className="movie__title">{title}</h3>
<h5 className="movie__year">{year}</h5>
<ul className="movie__genres">
{genres.map((genre, index) => (
<li key={index} className="genres__genre">{genre}</li>
))}
</ul>
<p className="movie__summary">{summary.slice(0, 180)}...</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,
genres: PropTypes.arrayOf(PropTypes.string).isRequired
}
export default Movie;
genre는 배열
slice -> css를 적용해서 출력할 때 summary는 0-180까지만 출력하고 이후는 ...으로 생략하기 위해 사용
[App.js]
import React from "react";
import axios from "axios";
import Movie from "./Movie";
class App extends React.Component {
state = {
isLoading: true,
movie: []
};
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 (<section className="container">
{isLoading ? (
<div className="loader">
<span className="loader_text">Loading...</span>
</div>
) : (
<div className="movies">
{movies.map(movie => (
<Movie
key={movie.id}
id={movie.id}
year={movie.year}
title={movie.title}
summary={movie.summary}
poster={movie.medium_cover_image}
genres={movie.genres}
/>
))}
</div>
)}
</section>);
}
}
export default App;
[결과]
[에러]
<ul className="genres">
{genres.map((genre, index) => (
<li key={index} className="genres__genre">{genre}</li>
))}
</ul>
[Movie.js] map에서 index는 0,1,2,3 와 같이 오름차순으로 붙는 숫자이다. 이것을 key로 지정
[5] css 추가
'🔐 Archive > ReactJS' 카테고리의 다른 글
[ReactJS error] event로 호출되는 함수 내의 함수가 안불러지는 이유? (0) | 2020.03.11 |
---|---|
[ReactJS: 삽질로 얻은 것들] local json파일 불러오기, State에 Props값을 저장하고 싶은 경우 등 (1) | 2020.03.11 |
[weather API] 날씨 API 사용해서 ReactJS로 웹페이지 만들기: 날씨 API 사용하는 방법 (0) | 2020.03.11 |
ReactJS로 웹서비스 만들기 3: State (0) | 2020.03.05 |
ReactJS로 웹서비스 만들기 2: Component (0) | 2020.03.05 |