2018. 4. 30. 23:45ㆍProgramming/ReactJS
4일차에 배울 것
1) Smart vs Dumb
2) AJAX로 데이터 가져오기
Smart(똑똑한) 컴포넌트와 Dumb(멍청한) 컴포넌트의 차이에 대해서 알아봅시다.
컴포넌트가 스마트해지려면 IQ도 아니고 SKY 학벌도 아니고 단지 state만 있으면 됩니다.
state가 있으면 smart 컴포넌트, state가 없으면 dumb 컴포넌트라고 부르는 것이죠.
현재까지 작성한 컴포넌트로 보자면,
App: state가 있으므로 Smart,
Movie: state가 없으므로 Dumb
인 것이 됩니다.
이제부터 리팩토링(코드를 유지보수에 좋게 가다듬는 것)을 할 것입니다.
먼저 Movie 컴포넌트의 코드를 봅시다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import React, {Component} from 'react'; import PropTypes from 'prop-types'; class Movie extends Component { render(){ console.log(this.props); return ( <div> <h1>{this.props.title}</h1> <img src={this.props.poster}/> </div> ); } } Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired } export default Movie; | cs |
Dumb 컴포넌트는 어떠한 필드나 내부 함수를 가지고 있지 않기 때문에
class 구조로 쓸 필요가 없습니다. 그래서 class 대신에 function으로 고칠 것입니다.
function으로 모두 고치면 다음과 같이 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import React from 'react'; import PropTypes from 'prop-types'; function Movie({title, poster}) { return (<div> <h1>{title}</h1> <img src={poster}/> </div> ) } Movie.propTypes = { title: PropTypes.string.isRequired, poster: PropTypes.string.isRequired } export default Movie; | cs |
고치기 전과 비교하면 많이 깔끔해졌죠?
여기서 자세히 보면 this.props가 없어졌다는 것을 알 수 있는데요.
this.props를 쓰지 않아도 전달되는 props를 받을 수 있다는 것을 기억하고 넘어가도록 하죠.
자 다음으로는 'AJAX로 데이터 가져오기'를 해보도록 하겠습니다.
일단 AJAX가 무엇인지 모르는 분들에게 간단히 설명하자면,
자바스크립트를 이용해 데이터를 가져오는 기술이라고 보면 됩니다.
좀 더 깊은 이해를 위해서는 아래 그림을 참고하시면 됩니다.
이 그림을 이해하기 쉽게 설명해 보겠습니다.
왼쪽의 기존 방식은 HTML과 리소스(css나 image 파일 등)을 서버에서 한 번에 보내줍니다.
반면에 오른쪽 AJAX는 웹페이지에 자바스크립트를 넣어두어서, 자바스크립트가 call(요청)되면 추가로 HTML과 리소스가 보내집니다.
기존 방식은 대형 마트에서 식료품을 대량 구매하는 것에 비해, AJAX는 편의점에서 필요할 때마다 음식을 사먹는 것에 비유할 수 있습니다.
대형 마트는 멀어서 여러 번 가기 힘들지만 편의점은 가까워서 금방 음식을 사올 수 있어서 더 편리한 거죠.
이렇듯이 AJAX를 쓰면 유저의 요청에 따라서 수시로 데이터가 변경되거나 할 수 있기 때문에 좀 더 쓰기 좋은 웹사이트를 만들 수 있습니다. 요즘에는 대부분의 웹사이트에서 AJAX가 쓰이기 때문에 웹개발자에게 있어서 거의 필수로 알아야 하는 부분이기도 합니다.
자 그럼 이 AJAX를 실제로 써봅시다.
보통 웹사이트에서는 자바스크립트 라이브러리인 제이쿼리(JQuery)를 이용해서 많이 쓰는데,
이번에는 제이쿼리를 쓰지 않기 때문에 대신에 fetch라는 것을 씁니다.
그럼 fetch를 이용해서 영화 데이터를 가져와 봅시다.
YTS 영화 릴그룹에서 제공하는 영화 정보 API에서 데이터를 가져옵니다.
영화 정보 API 사이트
https://yts.am/api
json, jsonp, xml 등 여러 데이터 포맷이 있는데 우리는 json을 가져올 것입니다.
과제) fetch를 이용해서 위 URL로부터 데이터를 가져오되 평점(rating) 순으로 정렬돼 있는 데이터를 가져오세요.
또한 가져온 데이터를 확인할 수 있게 브라우저 console에 출력해보세요.
힌트) 평점 순 정렬은 위 URL에 파라미터로 sort_by=rating을 붙여주면 됩니다.
데이터를 가져오는 동작은 단지 fetch 한 문장만 쓰면 됩니다.
여기까지 한 다음에 Chrome에서 Network 탭에 들어가 봅시다.
Network 탭에서는 통신 내역을 확인할 수가 있습니다. 찾아보시면 영화 리스트 데이터가 있는 것을 확인할 수 있습니다.
그 다음엔 Response 탭에 들어가면 통신 처리 결과가 나옵니다.
status OK 라는 것은 성공적으로 처리됐다는 것을 뜻합니다. Response 내용을 대충 훑어 보세요.
그러면 영화 이름이 들어 있는 것을 확인할 수 있습니다. 이는 성공적으로 영화 리스트 데이터를 가져왔음을 뜻합니다.
자 이제 이 데이터를 콘솔에 출력해봅시다.
fetch로 가져온 데이터를 이용하기 위해서는 promise를 사용하게 됩니다.
1 2 3 4 5 6 7 8 9 | componentDidMount() { fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating') //return promise .then(response => response.json()) //return promise .then(json => console.log(json.data.movies)) //return movie list(json) .catch(err => console.log(err)); setTimeout(() => { this.setState({isLoading:false}) }, 3000); } | cs |
Promise가 무엇인지 최대한 간단히 말하자면 하나의 약속입니다.
약속을 지키면 특정 동작이 실행되고 약속을 못 지키면 에러가 나오는 식입니다.
비유하는 식으로 한 번 설명해보겠습니다. 재벌집 아들내미가 한 명 있다고 합시다.
명문대학에 합격하면 자동차를 한 대 사주기로 했다고 합시다. 반면에 불합격하면 두들겨 맞기로 했다고 합시다.
fetch(아들내미 명문대 합격)
.then(자동차 한 대 사주기)
.catch(두들겨 맞기)
이런 상황은 promise로 이런 식으로 표현될 수 있습니다.
재벌집 아버지가 약속을 하나 더 붙여줄 수도 있고요. 아래와 같은 식으로요.
fetch(아들내미 명문대 합격)
.then(자동차 한 대 사주기)
.then(자동차 튜닝도 해주기)
.catch(두들겨 맞기)
Promise에 대해서는 밑의 블로그에서 잘 설명하고 있으니 참고하시기를 바랍니다.
http://programmingsummaries.tistory.com/325
이제 콘솔 출력은 되었으니 본격적으로 이 데이터를 movie state에 넣어보기로 하겠습니다.
이 경우에는 async/await 문법을 사용합니다. 이것도 promise와 비슷하게 비동기 처리에 이용되는 문법입니다.
모두 작성하면 다음과 같이 나옵니다.
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 | import React, { Component } from 'react'; import './App.css'; import Movie from './Movie'; class App extends Component { state = { movie : [], isLoading : true } componentDidMount(){ setTimeout(() => { this.setState({isLoading:false}); this._getMovies(); }, 3000); } _getMovies = async () => { const movie = await this._callApi(); this.setState({ movie // movie : movie와 동일 }) } _callApi = () => { return fetch('https://yts.am/api/v2/list_movies.json?sort_by=rating') .then(response => response.json()) .then(json => json.data.movies) .catch(err => console.log(err)); } _renderMovies() { const movies = this.state.movie.map((movie, index) => { return <Movie title={movie.title} poster={movie.poster} key={index}/> } ) return movies; } render() { return ( <div className="App"> { this.state.isLoading ? 'Now is Loading':this._renderMovies() } </div> ); } } export default App; | cs |
출력되는 내용을 보면 뭔가 잘못되었다는 것에 눈치채실 텐데요.
위와 같이 영화 포스터는 없고 타이틀명만 잔뜩 나와 있습니다.
왜 이런 일이 생긴 걸까요?
문제를 해결하기 위해서 한 번 디버깅을 해봅시다.
프로그래밍 경험이 꽤 있으신 분들은 어떻게 디버깅을 할 지 금방 아실 겁니다.
어느 포인트에서 console.log를 출력할 지도 금세 눈치채실 거구요.
1 2 3 4 5 6 7 | _getMovies = async () => { const movie = await this._callApi(); console.log(movie); this.setState({ movie // movie : movie와 동일 }) } | cs |
_getMovies 안의 3번째 줄에서 console.log를 브라우저에 출력해 보면,
json 안에 poster라는 key값이 없다는 것을 알 수 있습니다.
대신에 medium_cover_image라는 것이 있지요. 그러면 우리가 해야할 일은 간단합니다.
poster를 medium_cover_image로 바꿔주시면 되는 거죠.
바로 이렇게요.
1 2 3 4 5 6 7 | _renderMovies() { const movies = this.state.movie.map((movie, index) => { return <Movie title={movie.title} poster={movie.medium_cover_image} key={index}/> } ) return movies; } | cs |
저장한 후 다시 웹페이지에 들어가보면 제대로 출력이 되고 있음을 알 수 있습니다.
이것으로 영화 평점순 TOP 20의 영화 제목과 포스터를 출력하는 웹 페이지가 완성되었습니다.
간단한 리액트JS의 사용법을 익혔으니 앞으로 할 일은 이것을 응용하여 더 멋진 웹사이트를 만드는 일이 되겠습니다.
리액트JS로 웹 서비스 만들기 강의는 이것으로 마치도록 하겠습니다.
모두 수고하셨습니다.
'Programming > ReactJS' 카테고리의 다른 글
[튜토리얼] Next.js 프로젝트 시작하기 2편 (CSS 스타일링에서 Vercel을 통한 배포까지) (2) | 2024.09.12 |
---|---|
[튜토리얼] Next.js 프로젝트 시작하기 1편 (초기 세팅에서 페이지 작성까지) (2) | 2024.09.11 |
리액트JS로 웹 서비스 만들기 3일차 (0) | 2018.04.23 |
리액트JS로 웹 서비스 만들기 2일차 (0) | 2018.04.21 |
리액트JS로 웹 서비스 만들기 1일차 (0) | 2018.04.08 |