만들면서 배우는 리액트 튜토리얼 - 7.Async와 Await
이전에 배운 Promise의
.then만 사용하면 프로그램이 커졌을 때
.then .then .then이 끝없이 반복되는 '콜백 지옥'에 빠질 수 있다.
하지만 Async와 Await을 사용하면 이 문제를 깔끔하게 해결할 수 있다.
Cf) await은 async 함수 내에서만 동작한다.
import React, { Component } from 'react';
import './App.css';
import Movie from './Movie'
class App extends Component {
state = [
]
componentDidMount() {
this._getMovies();
}
_renderMovies = () => {
const movies = this.state.movies.map((movie, index) =>
<Movie title={movie.title} poster={movie.large_cover_image} key={movie.id}
/>
)
return movies
}
_getMovies = async () => {
// await은 그 함수가 successed가 아니라 just finished되면
// 그 return value가 무엇이든 그 value를 return한다
const movies = await this._callApi()
// 따라서 _callApi()가 끝나기 전까지 setState()는 실행되지 않는다
this.setState({
movies // ES5 movies: movies
})
}
_callApi = () => {
// fetch라는 이름의 promise를 return
return fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating')
.then(potato => potato.json()) // 사람이 읽을 수 있게 byte -> json으로 변경
.then(json => json.data.movies)
.catch(err => console.log(err))
}
render() {
return (
<div className="App">
{/*
this.state.movies 데이터가 존재하면 기존 state mapping을 실행하고,
아니면 Loading... string을 띄워준다
*/}
{this.state.movies ? this._renderMovies() : "Loading..."}
</div>
);
}
}
export default App;
Async,
Await 예시
componentDidMount()에는 주로 많은 함수들이 실행된다.
그렇기 때문에 componentDidMount() 코드 사이즈를 줄이기 위해서 위 코드에서는
기존 내용을 _getMovies()라는 이름의 함수로 새로 선언해서 사용했다.
_getMovies는 동시에 여러 API를 이용하여 데이터를 가지고 올 수 있도록 asnyc를 이용했고
Api로부터의 데이터 로딩이 다 끝나지 않았을 때 setState가 실행되면 안되기 때문에
_callApi()는 await을 사용했다.
즉, 데이터는 여러 군데에서 동시에 가져올 수 있지만 그 데이터를 state로 넘기는 것은
모든 데이터가 로딩된 뒤에 실행된다는 것이다.
_callApi()는 기존 fetch 코드를 거의 재사용 했는데 우선 fetch promise를
JSON형태로 바꾸고(.then(potato => potato.json())) json.data.movies을 통해
그 데이터 중에서 movies 데이터를 뽑아 return한다.
movies 객체 안에 더 이상 우리가 만들었던 poster라는 데이터는 없고 대신
large_cover_image가 존재하기 때문에 poster={movie.large_cover_image} 로 코드를 변경했다.
마지막으로
컴포넌트의 key에 map에서 자동생성된 index를 사용하는 것이 너무 느리고
이제
각 영화 데이터에 id가 존재하기 때문에 key={movie.id}로 바꿔주었다.
0 comments