유튜브 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>