티스토리 뷰

유튜브 Data API(v3)를 활용한 비디오 렌더링

index.js

import _ from 'lodash';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
import YTsearch from 'youtube-api-search';

/* 보안상 이유로 비공개 */
const API_KEY = '';

class App extends Component {
    constructor(props) {
        super(props);
        
        this.state = { 
            videos:[],
            selectedVideo: null 
        }; 
        this.videoSearch('surfboard');  
    }
    videoSearch(term) {
        YTsearch({key: API_KEY, term: term}, (videos) => {
            this.setState({ 
                videos: videos,
                selectedVideo: videos[0]
            })
        })    
    }  
    render() {
        const videoSearch = _.debounce((term) => {this.videoSearch(term)}, 300);
        return (
            <div>
                <SearchBar onSearchTermChange={videoSearch} /> 
                {/* 원래는 term=>this.videoSearch(term) */}
                <VideoDetail video={this.state.selectedVideo}/>
                <VideoList 
                    onVideoSelect = {selectedVideo => this.setState({selectedVideo})}
                    videos = {this.state.videos}/>
            </div>
        )
    }
}

ReactDOM.render(<App />, document.querySelector('.container'));
  • import한 것들
    • 기본적으로 버츄얼 돔에 렌더링하는 것을 도와주는 react-dom, 컴포넌트 만드는데 필요한 react, 그 외에 웹앱을 구성할 컴포넌트 js 파일들, 라이브러리 lodash, 유튜브 서치를 위해 필요한 youtube-api-search
  • youtube api key
    • 보안상의 이유로 빈 스트링으로 표현했다. 원래는 api 키를 저렇게 변수에 할당하여 사용했다.
  • index.js
    • 가장 부모가 되는 클래스 컴포넌트 App이 위치한 파일이다. 이 컴포넌트를 통해 다른 자식들에게 값이나 함수를 pass해서 보내고, 결과를 돔에 렌더링한다.
  • 클래스 컴포넌트의 구조
    • 다른 포스팅에도 써놓긴 했지만, 리액트는 함수형 컴포넌트와 클래스 컴포넌트로 나뉘는데, 저렇게 class extends 구문을 사용하여 작성한다. 클래스 컴포넌트 안에는 기본적으로 constructor가 존재하고 그 안에 super(props), this.state({})가 위치한다.
    • 클래스 컴포넌트는 state를 가질 필요가 있을 때 만드는 것이므로 컨스트럭터 내의 this.state 구문을 통해 state를 초기화한다.
  • this.state()
    • 이 웹앱은, 유튜브 api를 활용하여 유튜브의 비디오들을 검색하고 그 결과를 화면상에 보여주는 것이 목적이다.
    • 그래서 app이 가져야 할 스테이트는 검색 결과를 유튜브에 요청하여 받아서 가지고 있을 videos(배열), 그리고 검색된 결과 중 사용자가 선택한 비디오인 selectedVideo이다.
  • videoSearch 함수
    • 비디오 서치함수는 말 그대로 인풋창에 검색하고자 하는 키워드를 받아서 이를 유튜브에 요청하기 위해 만든 것이다. 후에 렌더링하기 쉽도록 별도 함수로 만들었다.
    • 임포트해온 YTsearch의 첫번째 아규먼트로는 api key와 검색하고자 하는 term을 넘기고, 두번째 아규먼트로는 그 term에 대한 요청 결과를 받아서 어떻게 처리할지 콜백함수를 사용한다.
    • 여기서 this.setState()를 사용했는데, this.state가 스테이트를 초기화하기 위해 컨스트럭터 내에 사용하는 것이라면 setState는 스테이트를 업데이트하고자 할 때 사용하는 것이다. 요청한 결과를 가져와서 videos 프로퍼티에 키값으로 업데이트하고, 그 배열 중 0번째 인덱스 원소를 selectedVideo에 업데이트하도록 했다.
  • render()
    • 클래스 컴포넌트들은 렌더 함수를 가져야 하고, 그 안에 return을 한다.
    • 리턴을 하기 전에 리턴문 안에 사용하기 위한 const videoSearch를 선언했다. 이는 검색을 할 때에 검색이 실시간으로 일어나는 것을 방지하기 위해서 사용한 것이다. 예를 들어 bts을 검색하려고 하면 b, bt, bts 이런 식으로 글자가 입력될 때마다 검색이 일어나기 때문에, 결과적으로 원하는 검색 결과를 얻어오기까지 시간이 더 걸린다. 로대쉬 라이브러리의 denounce 메서드를 사용하여 즉시가 아니라 300밀리세컨 뒤에 term이 videoSearch함수로 전달되도록 하였다.
  • return
    • SearchBar 인스턴스여기서 search_bar.js로 넘어가서 코드를 보아야될 것 같지만… 그러면 또 다시 index.js로 돌아와야 되기 때문에 일단 여기서는 index.js에서 작성된 코드들만 리뷰하겠다!
    • 서치바 인스턴스에는 onSearchTermChange라는 변수를 작성하여 pass했다. 이는 위에서 로대쉬의 denounce가 적용된 videoSearch를 전달한 것이다. 로대쉬함수를 적용한 변수를 넣기 전에는 그냥 onSearchTermChange={term => this.videoSearch(term)} 이었다. 여기서 this가 붙은 이유는, render함수가 콜되기 전에 선언된 함수라서 그렇다. 로대쉬가 적용된 건 render함수 안에 있어서 this가 필요없다.
    • VideoDetail 인스턴스
    • 비디오 디테일 컴포넌트는 가장 메인에 보이는 비디오라고 할 수 있다. 유튜브를 볼 때에 내가 선택한 비디오가 가장 크게 화면에 나타나고, 그 옆에는 다른 비디오 리스트가 섬네일과 함께 떠있게 된다. 즉 비디오 디테일 컴포넌트는 사용자가 볼 메인 비디오를 띄워놓는 컴포넌트이다. 따라서 여기에는 state의 selectedVideo를 video라는 변수로 pass하고 있다.
    • VideoList 인스턴스인스턴스에 유튜브 검색결과인 this.state.videos를 패스하고 있으며, onVideoSelect는 콜백함수로 selectedVideo를 업데이트하고 있다. 사용자가 리스트에서 특정 아이템을 선택하면 이 함수로 전달되어서 setState를 통해 selectedVideo 상태가 업데이트될 것이고, 이 것은 다시 비디오 디테일에 전달되어 렌더링될 것이다.
    • 비디오 리스트는 메인 비디오 옆에 띄워놓게 되는 다른 비디오들의 리스트이다. 헷갈리는 부분은 VideoListItem 컴포넌트가 따로 있다는 점이다. 이는 리스트를 구성하는 각각의 아이템 컴포넌트이다. 그래서 App 컴포넌트를 통해 비디오 리스트로 전달된 것들은 다시 각각의 비디오 리스트 아이템으로 전달될 것이다. (컴포넌트를 두 번 거치기 때문에 헷갈릴 수 있다)
  • ReactDOM.render
    • 다른 포스팅에서 이미 작성한 내용이지만, react-dom에게 렌더링하라고 명령하는 메서드이다. 메인이 되는 앱 컴포넌트를 instantiate해서 pass하고, 돔의 어디에 렌더링할지 두번째 아규먼트로 전달하고 있다.
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함