React - Review - 09
Review React
지금까지 배운 내용으로 Youtube API를 가져와 화면에 출력해주는 프로젝트를 만든다.
Accessing the Youtube API
-
console.developers.google.com 접속
-
프로젝트 생성 (CORS off!)
-
사용할 API Library 선택 -> 사용 설정 버튼 클릭
-
메뉴에서
사용자 인증 장소 선택 -> CREATE CREDENTIAL 선택 -> 프로젝트에 맞도록 선택 후 확인 버튼 클릭
-
사용자 인증 정보 복사(API key)
-
AIzaSyD1pBSnrieKIUvBwQACF2f0bzvZum1C0AY
-
키 제한사항 -> HTTP referrers(web sites) -> localhost:3001 작성 (다른 사람이 사용할 수 있기 때문)
import axios from 'axios';
const KEY = 'Your API Key';
export default axios.create({
baseURL: 'https://www.googleapis.com/youtube/v3',
params: {
part: 'snippet',
maxResults: 5,
key: KEY,
q: 'surfboards'
}
});
Passing Props Parent Component
import React from 'react';
import SearchBar from './SearchBar';
import youtube from '../apis/youtube';
class App extends React.Component {
onTermSubmit = term => {
youtube.get('/search', {
params: {
q: term
}
});
};
render() {
return (
<div className="ui container">
<SearchBar onFormSubmit={this.onTermSubmit} />
</div>
)
};
}
export default App;
import React from 'react';
class SearchBar extends React.Component {
state = { term: '' };
onInputChange = event => {
this.setState({ term: event.target.value });
};
onFormSubmit = event => {
event.preventDefault();
this.props.onFormSubmit(this.state.term );
};
render() {
return (
<div className="search-bar ui segment">
<form onSubmit={this.onFormSubmit} className="ui form">
<div className="field">
<label>Video Search</label>
<input
type="text"
value={this.state.term}
onChange={this.onInputChange}
/>
</div>
</form>
</div>
);
}
}
export default SearchBar;
Network tab에서 아래와 같이 데이터가 넘어 오는 것을 확인할 수 있다.
Updating State with Fetched Data
import React from 'react';
import SearchBar from './SearchBar';
import youtube from '../apis/youtube';
class App extends React.Component {
state = { videos: [] };
onTermSubmit = async term => {
const response = await youtube.get('/search', {
params: {
q: term
}
});
this.setState({ videos: response.data.items });
};
render() {
return (
<div className="ui container">
<SearchBar onFormSubmit={this.onTermSubmit} />
I have {this.state.videos.length} videos.
</div>
)
};
}
export default App;
Passing State as Props
Add VideoList.js
import React from 'react';
const VideoList = props => {
return (
<div>{props.videos.length}</div>
)
};
export default VideoList;
render() {
return (
<div className="ui container">
<SearchBar onFormSubmit={this.onTermSubmit} />
<VideoList videos={this.state.videos} />
</div>
)
};
Rndering a List of Videos
Add VideoItem.js
import React from 'react';
const VideoItem = (props) => {
return (
<div>Video Item</div>
)
};
export default VideoItem;
import React from 'react';
import VideoItem from './VideoItem';
const VideoList = ({ videos }) => {
const renderedList = videos.map((video) => {
return <VideoItem />
});
return (
<div>{renderedList}</div>
)
};
export default VideoList;
Rendering Video Thumbnails and Styling a List
import React from 'react';
const VideoItem = ({ video }) => {
return (
<div className="video-item item">
<img className="ui image" src={video.snippet.thumbnails.medium.url} />
<div className="content">
<div className="header">{video.snippet.title}</div>
</div>
</div>
);
};
export default VideoItem;
import React from 'react';
import VideoItem from './VideoItem';
const VideoList = ({ videos }) => {
const renderedList = videos.map((video) => {
return <VideoItem video={video} />
});
return (
<div className="ui relaxed divided list">{renderedList}</div>
)
};
export default VideoList;
.video-item {
display: flex !important;
align-items: center !important;
cursor: pointer;
}
.video-item.item img {
max-width: 180px;
}
Conditional Rendering
state = { videos: [], selectedVideo: null };
onVideoSelect = (video) => {
this.setState({ selectedVideo: video });
};
render() {
return (
<div className="ui container">
<SearchBar onFormSubmit={this.onTermSubmit} />
<VideoDetail video={this.state.selectedVideo} />
<VideoList onVideoSelect={this.onVideoSelect} videos={this.state.videos} />
</div>
)
};
const VideoList = ({ videos, onVideoSelect }) => {
const renderedList = videos.map((video) => {
return <VideoItem onVideoSelect={onVideoSelect} video={video} />
});
return (
<div className="ui relaxed divided list">{renderedList}</div>
)
};
const VideoItem = ({ video, onVideoSelect }) => {
return (
<div onClick={() => onVideoSelect(video)} className="video-item item">
<img className="ui image" src={video.snippet.thumbnails.medium.url} />
<div className="content">
<div className="header">{video.snippet.title}</div>
</div>
</div>
);
};
import React from 'react';
const VideoDetail = ({ video }) => {
if (!video) {
return <div>Loading...</div>
}
return (
<div>{video.snippet.title}</div>
);
};
export default VideoDetail;
Displaying a Video Player
import React from 'react';
const VideoDetail = ({ video }) => {
if (!video) {
return <div>Loading...</div>
}
const videoSrc = `https://www.youtube.com/embed/${video.id.videoId}`;
return (
<div>
<div className="ui embed">
<iframe src={videoSrc} />
</div>
<div className="ui segment">
<h4 className="ui header">{video.snippet.title}</h4>
<p>{video.snippet.description}</p>
</div>
</div>
);
};
export default VideoDetail;
Fixing a Few Warnings
console에
Each child in an array or iterator should have a unique "key" prop.라는 에러와 여러 경고들이 출력된다.
<img alt={video.snippet.title} className="ui image" src={video.snippet.thumbnails.medium.url} />
const renderedList = videos.map((video) => {
return <VideoItem key={video.id.videoId} onVideoSelect={onVideoSelect} video={video} />
});
<iframe title="video player" src={videoSrc} />
render() {
return (
<div className="ui container">
<SearchBar onFormSubmit={this.onTermSubmit} />
<div className="ui grid">
<div className="ui row">
<div className="eleven wide column">
<VideoDetail video={this.state.selectedVideo} />
</div>
<div className="five wide column">
<VideoList onVideoSelect={this.onVideoSelect} videos={this.state.videos} />
</div>
</div>
</div>
</div>
)
}
Defaulting Video Selection
새로고침하면 buildings 검색어가 자동 검색되도록 수정한다.
componentDidMount() {
this.onTermSubmit('buildings');
};
onTermSubmit = async term => {
const response = await youtube.get('/search', {
params: {
q: term
}
});
this.setState({
videos: response.data.items,
selectedVideo: response.data.items[0]
});
};
GitHub and Others
댓글
댓글 쓰기