[React] Movie app clone coding : Async Await in React
6-3. Async Await in React
Async, Await
1componentDidMount(){
2 fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating')
3 .then(response => response.json())
4 .then(json => console.log)
5 .catch(err => console.log('error'))
6}
Async
와 Await
는 위 코드들을 좀더 분명하게 작성해주는 도구이다.
영화들을 state에 올리려면 아래와 같은 작업을 해야 한다. 하지만 세련되지 않고, 어플리케니션으 크면 then 안에 then으로 이어지면서 callback hell
에 빠지게 된다. 그래서 Async
, Await
를 쓸 것이다.
1.then(json =>{
2 this.setState({
3 movies: json.data.movies
4 })
5 .then(() => .then()) // ... callback hell
6})
Async, Await 적용
먼저 새로운 function을 두개 만든다.
1// App.js
2_getMovies = () => {}
3_callApi = () => {}
큰 사이즈의 componentDidMount
를 갖고 싶지 않으므로, 안에 있던 내용을 _callAPI
로 옮기고, this._getMovies()
를 작성한다. 작은 function들이 각기 다른 곳에 있는 것이 좋다.
1// App.js
2componentDidMount(){
3 this._getMovies(); // 큰 사이즈의 componentDidMount를 갖고 싶지 않으므로
4}
5
6_getMovies = () => {
7
8}
9
10_callApi = () => {
11 fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating')
12 .then(response => response.json())
13 .then(json => console.log)
14 .catch(err => console.log('error'))
15}
그다음 async
라는 것을 한다. (asynchronous
)
1_getMovies = async() => {}
이 안에 await
라는 것을 작성한다.
1_getMovies = async() => {
2 const movies = await this._callApi()
3}
didMount
하고 나면, get movies
를 한다. 그리고 이것은 asynchronous function
인데 movie
라는 variable
을 갖고 있는 것이다. 그리고 movie
는 callApi
라는 function을 await
모드에서 value
를 갖고 있다.
1_getMovies = async() => {
2 const movies = await this._callApi()
3 this.setState({
4 movies
5 })
6}
await
하는 것은 callApi
기능이 끝나는 것을 기다리고(성공적인 수행이 아니라 끝나는 것을 기다린다), callApi
의 return value
가 무어이든 그 value
를 movies
에 넣는다.
다시 정리하면, callApit
의 return value
를 movies
에 set
한다. 그리고 해당 컴포넌트의 setState
를 movies
로 할 것이다. 이것은 this._callApi
의 return value
이다.
this.setState({ movies })
부분은 setstate
는 callApi
작업이 완료되기 전까지 실행되지 않는다.
callApi
작업이 완료된 후에 this.setState({ movies })
가 실행된다. 이를 하는 방법은 아래 코드와 같다.
fetch
라는 이름의 promise
를 return 한다.
1_callApi = () => {
2 return fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating')
3 .then(response => response.json())
4 .then(json => json.data.movies)
5 .catch(err => console.log('error'))
6}
movie object
가 변경되었으므로 _renderMovies
의 코드를 아래와 같이 수정해준다.
1_renderMovies = () => {
2 const movies = this.state.movies.map((movie, index) => {
3 return <Movie title={movie.title} poster={movie.large_cover_image} key={movie.id} />
4 // poster = movie.large_cover_image, key = movie.id 로 수정
5 })
6 return movies
7}
component의 key는 느리기 때문에 인덱스를 사용하는 것은 좋지않다. 그러므로 key
로 movie.id
를 사용한다.
정리
fetch
를callApi
로 변경getMovies
라는 asynchronous function 작성- 그 안에
movies
라는const variable
생성 callApi
작업이 완료되고 return 하는 것을await
함callApi
는fetch promise
를 return하는데, 데이터는 Json- 그러므로
json.data.movies
라는 value는const movies
의 결괏값이 되는 것 - 그리고 component의
state
를movies
로set
한 것 state
안에movies
가 있으면render movies
라는 fucntion 을 불러옴render movies
는movies
라는 const를 불러오는데 이는 타이틀, 포스터 순으로 맵핑 함
전체코드
1// App.js
2import React, { Component } from 'react';
3import './App.css';
4import Movie from './Movie';
5
6class App extends Component {
7
8 state = {}
9
10 componentDidMount(){
11 this._getMovies(); // 큰 사이즈의 componentDidMount를 갖고 싶지 않으므로
12 }
13
14 _renderMovies = () => {
15 const movies = this.state.movies.map((movie, index) => {
16 return <Movie title={movie.title} poster={movie.large_cover_image} key={movie.id} />
17 })
18 return movies
19 }
20
21 _getMovies = async() => {
22 const movies = await this._callApi()
23 this.setState({
24 movies
25 })
26 }
27
28
29 _callApi = () => {
30 return fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating')
31 .then(response => response.json())
32 .then(json => json.data.movies)
33 .catch(err => console.log('error'))
34 }
35
36
37 render() {
38 return (
39 <div className="App">
40 {this.state.movies ? this._renderMovies() : 'Loading'}
41 </div>
42 );
43 }
44}
45
46export default App;