我正在编写我的第一个React应用程序,而且我遇到了Youtube API的问题。我写了一个单独的Youtube搜索功能,如:
var searchYouTube = (options, callback) => {
$.get('https://www.googleapis.com/youtube/v3/search', {
key: window.YOUTUBE_API_KEY,
q: options.query,
maxResults: options.max,
}).done(function(data) {
console.log(data);
callback(data);
});
};
window.searchYouTube = searchYouTube;
每次搜索输入发生变化时都会触发。你可以在我的app.jsx中看到这个组件:
class App extends React.Component {
constructor() {
super();
this.state = {
videos: exampleVideoData,
currentVideo: exampleVideoData[0]
};
}
renderSearch(term) {
console.log($(term.target).val());
this.setState({
videos: searchYouTube({query:$(term.target).val(),max:5})
});
}
setVideo(video) {
this.setState({
currentVideo: video
});
}
render() {
return (
<div>
<nav className="navbar">
<div className="col-md-6 offset-md-3">
<div><Search renderSearch={this.renderSearch.bind(this)}/></div>
</div>
</nav>
<div className="row">
<div className="col-md-7">
<div><VideoPlayer currentVideo={this.state.currentVideo}/></div>
</div>
<div className="col-md-5">
<div><VideoList videos={this.state.videos} setVideo={this.setVideo.bind(this)}/></div>
</div>
</div>
</div>
);
}
}
// In the ES6 spec, files are "modules" and do not share a top-level scope
// `var` declarations will only exist globally where explicitly defined
window.App = App;
最后,我得到的错误是:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required parameter: part",
"locationType": "parameter",
"location": "part"
}
],
"code": 400,
"message": "Required parameter: part"
}
}
有关我需要重组的任何建议吗?我相信它是searchYoutube函数的结构。也许我错过了一个参数?
答案 0 :(得分:0)
控制台日志清晰:
"message": "Required parameter: part",
表示您必须在选项中添加part
。我建议添加以下内容:
var searchYouTube = (options, callback) => {
$.get('https://www.googleapis.com/youtube/v3/search', {
key: window.YOUTUBE_API_KEY,
q: options.query,
part: 'snippet', // this one was missing
maxResults: options.max,
}).done(function(data) {
console.log(data);
callback(data);
});
};
它会起作用。别担心!和演示如下:
const { Component } = React;
class SearchBar extends Component {
state = { term: '' };
render() {
return (
<div className="search-bar">
<input
value={this.state.term}
onChange={event => this.onInputChange(event.target.value)}
/>
</div>
);
}
onInputChange = term => {
this.setState({ term });
this.props.onSearchTermChange(term);
};
}
const VideoDetail = ({ video }) => {
if (!video) {
return <div>Loading...</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} />
</div>
<div className="details">
<div>
{video.snippet.title}
</div>
<div>
{video.snippet.description}
</div>
</div>
</div>
);
};
const VideoListItem = ({ video, onVideoSelect }) => {
const imageUrl = video.snippet.thumbnails.default.url;
return (
<li onClick={() => onVideoSelect(video)} className="list-group-item">
<div className="video-list media">
<div className="media-left">
<img className="media-object" src={imageUrl} />
</div>
<div className="media-body">
<div className="media-heading">
{video.snippet.title}
</div>
</div>
</div>
</li>
);
};
const VideoList = props => {
const videoItems = props.videos.map(video => {
return (
<VideoListItem
onVideoSelect={props.onVideoSelect}
key={video.etag}
video={video}
/>
);
});
return (
<ul className="col-md-4 list-group">
{videoItems}
</ul>
);
};
const InvalidApiKey = () => (<h1>Sorry you do not give a valid YOUTUBE API key. Refresh the page or Run the snippet again and give a valid API key. </h1>)
class App extends Component {
state = {
videos: [],
selectedVideo: null,
error: false
};
componentDidMount() {
this.videoSearch('Sport');
}
searchYouTube(options, callback) {
$.get('https://www.googleapis.com/youtube/v3/search', {
key: this.props.youtubeApiKey,
q: options.query,
part: 'snippet',
maxResults: options.max
}).done(function(data) {
callback(data);
}).fail(() => this.setState({error: true}))
}
videoSearch = (term) => {
this.searchYouTube({ key: this.props.youtubeApiKey, term: term }, data => {
this.setState({
videos: data.items,
selectedVideo: data.items[1]
});
});
}
render() {
// const videoSearch = _.debounce(term => {
// this.videoSearch(term);
// }, 300);
if (this.state.error) return <InvalidApiKey />
return (
<div>
<SearchBar onSearchTermChange={this.videoSearch} />
<VideoDetail video={this.state.selectedVideo} />
<VideoList
onVideoSelect={selectedVideo => this.setState({ selectedVideo })}
videos={this.state.videos}
/>
</div>
);
}
}
const youtubeApiKey = prompt(
'Give a valid YOUTUBE API KEY and everything should work: '
);
ReactDOM.render(
youtubeApiKey
? <App youtubeApiKey={youtubeApiKey} />
: <InvalidApiKey />,
document.querySelector('#app')
);
.search-bar {
margin: 20px;
text-align: center;
}
.search-bar input {
width: 75%;
}
.video-item img {
max-width: 64px;
}
.video-detail .details {
margin-top: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
.list-group-item {
cursor: pointer;
}
.list-group-item:hover {
background-color: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app" />