티스토리 뷰

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

search_bar.js

import React, {Component} from 'react';


class SearchBar extends Component {
    constructor(props) {
        super(props);

        this.state = { term: '' }
    }
    render() {
        return (
            <div className="search-bar">
                <input onChange = {event => this.onInputChange(event.target.value)} />
            </div>
        )
    }
    
    onInputChange(term) {
        this.setState({term});
        this.props.onSearchTermChange(term); 
    }
}


export default SearchBar;
  • 서치바 컴포넌트 구조
    • 클래스 컴포넌트 - 사용자가 search한 term을 인풋으로 입력받아서 state로 가지고 있어야 하기 때문에 클래스 컴포넌트 구조이다.
    • 검색어를 입력받을 인풋 태그와, 그 안의 입력 이벤트를 처리하는 onChange
    • onChange 내에서 입력받은 event.target.value 를 다시 onInputChange라는 함수에 아규먼트로 전달한다.
    • onInputChange 함수는 코드를 깔끔하게 쓰기 위해서 리팩토링한 것이다. 아규먼트가 들어오면 setState구문을 통해 term을 업데이트하고, 또한 onSearchTermChange 함수에 아규먼트를 전달한다.
  • onSearchTermChange(결국 다시 index.js 부분의 일부 코드를 가져왔다.) 여기서 videoSearch함수는 키와 term을 보내서 결과를 받아 스테이트를 업데이트하는 함수이고, 이 함수를 onSearchTermChange라는 이름으로 서치바 인스턴스에 패스한 것이다.
  • 즉 서치바 컴포넌트 내에서 onSearchTermChange 함수에 사용자가 입력한 term을 아규먼트로 전달하면 이것이 state에 업데이트된다는 의미이다. 이는 유튜브 api search를 통해서 검색 결과를 videos에 업데이트할 것이고, 이것이 또 각 컴포넌트들에 전달될 것이다.
  • // index.js, App Component class App extends Component { ... 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 ( ... <SearchBar onSearchTermChange ={videonSearch} /> ... ) } }

 

video_detail.js

import React from 'react'; 

const VideoDetail = ({video}) => {
    if(!video) {
        return <div>Lodading...</div>
    }
    const videoId = video.id.videoId;
    const url = `https://www.youtube.com/embed/${videoId}`;
    return (
        <div className="video-detail col-md-8">
            <div className="embed-responsive embed-responsive-16by9">
                <iframe className="embed-responsive-item" src={url}></iframe>
            </div>
            <div className="details">
                <div>{video.snippet.title}</div>
                <div>{video.snippet.description}</div>
            </div>
        </div>
    )
}

export default VideoDetail;
  • 비디오 디테일 컴포넌트 구조
    • 비디오 디테일은 메인 비디오를 보여주기 위해 만든 컴포넌트이므로, App 컴포넌트에서 selectedVideo를 video라는 이름으로 pass받아 렌더링한다.
  • loading...
    • 요청 결과가 아직 업데이트되지 않았음에도 리액트는 즉시 렌더링하기 때문에, 넘겨받은 video가 아직 undefined된 상태에서 렌더링 시도가 일어날 수 있다. 이 때 에러 발생을 방지하기 위해서 video가 undefined된 상태일 때 loading 문자열을 돔에 띄우도록 했다.
  • bootstrapindex.html에 위처럼 부트스트랩을 넣어놨기 때문에 이를 사용하여 레이아웃을 짤 수 있다.
    • 비디오디테일의 className = video-detail이라는 div영역은 col-md-8 이라는 부트스트랩 예약어로 크기가 조절된다. 부트스트랩은 반응형 레이아웃을 제공하는데, 기본적으로 웹페이지의 한줄은 12개로 분할한다. 즉 col-md-1 이 12개가 들어갈 수 있고, col-md-8은 col-md-4와 함께 한줄을 다 커버할 수 있다. 그러니까 웹페이지가 최대 크기일 때 그 중에 2/3 정도를 차지하는 크기로 너비를 잡겠다는 것이 col-md-8 인 셈이다.
    • video-detail div는 두개의 div로 나뉘는데 하나는 영상, 하나는 타이틀 및 디스크립션을 넣을 부분이다. 첫번째 div는 embed-responsive-16by9 라고 쓰여있는데 이는 부트스트랩의 도큐멘테이션을 참조하면 되는 문법이다. 16, 9 라는 숫자는 동영상의 화면 비율이 16:9라는 의미이다.그 다음 details 클래스는 title과 description을 JSX로 넣은 것이 전부다.
    • (부트스트랩 홈페이지)
  • <!--index.html--> <head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css"> </head>

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함