我正在将React S和Rails,AWS S3用于youtube副本。我无法在观看页面中点击视频链接(从react-router创建)。例如,我将在/ watch / 4中查看内容,但是当我在/ watch / 19中单击内容链接时,URL将更改为/ watch / 19,但其他所有内容都将保持不变,并且我正在观看的内容将继续播放。
我有一个VideoContainer,通过它我可以显示另一个包含html视频标签的组件VideoPlayer。我正在VideoContainer级别上获取内容,并将内容的URL传递给VideoPlayer。我要获取的内容基于我从App的道具
派生的内容ID应用级别:
<Switch>
<Route path="/watch/:videoID" render={() => <VideoContainer props={this.props} user={this.state.user} getUser={this.getUser} />} />
</Switch>
export default withRouter(App);
视频容器级别:
import React from 'react'
import VideoPlayer from '../components/VideoPlayer'
import { Grid, Card } from 'semantic-ui-react'
import NavBar from './NavBar'
import ContentCard from '../components/ContentCard'
export default class VideoContainer extends React.Component {
constructor(props) {
super(props)
let contentID = this.props.props.location.pathname.split('/')[2]
this.state = {
contentID: contentID,
url: '',
name: '',
uploader: '',
favorite: '',
favoriteID: '',
user: this.props.user,
sideBarContent: []
}
}
checkIfFavorite = (id) => {
if (this.props.user) {
let favorite = this.props.user.favorites.filter(favorite => {
return favorite.content_id === parseInt(id)
})
if (favorite.length === 1) {
return true;
} else {
return false;
}
}
}
fetchContent(id) {
fetch(`http://localhost:3000/api/v1/content/${id}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(json => {
if (json.content !== null) {
this.setState({url: json.content.url, name: json.content.name, uploader: json.content.user.e_mail})
}
})
}
deleteFavorite = e => {
let contentID = this.props.props.location.pathname.split('/')[2]
let favorite = this.props.user.favorites.filter(favorite => {
return favorite.content_id === parseInt(contentID)
})[0]
let data = {
favorite: {
favorite_id: favorite.id
}
}
fetch(`http://localhost:3000/api/v1/favorites/${favorite.id}`, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(json => {
this.props.getUser()
})
}
addFavorite = e => {
let data = {
favorite: {
content_id: this.state.contentID,
user_id: this.props.user.user.id,
name: this.state.name
}
}
fetch('http://localhost:3000/api/v1/favorites', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(json => {
this.props.getUser()
})
}
fetchSidebarContent = () => {
fetch('http://localhost:3000/api/v1/content', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(json => {
let videosToPick = this.randomIntsFromRange(0, json.length-1, json)
let content = []
videosToPick.forEach(video => content.push(json[video]))
this.setState({sideBarContent: content})
console.log(this.state.sideBarContent)
})
}
randomIntsFromRange = (min, max, json) => {
let randomInts = []
let num;
while (randomInts.length < 6) {
num = Math.floor(Math.random() * (max-min+1)+min);
if (!randomInts.includes(num) && json[num].name !== this.state.name) {
randomInts.push(num)
}
}
return randomInts
}
componentDidMount() {
let contentID = this.props.props.location.pathname.split('/')[2]
if (this.props.user === null) {
this.props.getUser()
.then(this.fetchContent(contentID))
.then(this.fetchSidebarContent())
}
}
componentDidUpdate(prevProps, prevState) {
let contentID = this.props.props.location.pathname.split('/')[2]
if (contentID !== prevState.contentID) {
this.props.getUser()
.then(this.fetchContent(contentID))
.then(this.fetchSidebarContent())
.then(this.setState({contentID: contentID}))
}
}
render() {
console.log(this.state.favorite)
let contentID = this.props.props.location.pathname.split('/')[2]
let contentArr = [];
if (this.state.sideBarContent.length > 0) {
this.state.sideBarContent.forEach(content => {
contentArr.push(<ContentCard key={content.id} content={content} />)
})
} else {
this.fetchSidebarContent()
}
return(
<Grid padded container style={{height: '100vh', width: '100vw'}}>
<Grid.Row stretched style={{height: '100%'}}>
<Grid.Column textAlign='center' width={2}>
<NavBar />
</Grid.Column>
<Grid.Column textAlign='left' width={10}>
<Grid.Row style={{height: '4%'}}>
</Grid.Row>
<Grid.Row stretched style={{height: '96%'}}>
{this.state.url ? (
<>
<VideoPlayer src={this.state.url} />
<h2>{this.state.name}</h2>
<h4>Uploaded by: {this.state.uploader}</h4>
{this.checkIfFavorite(this.props.props.location.pathname.split('/')[2]) ? (<button onClick={this.deleteFavorite}>Unfavorite</button>) : (<button onClick={this.addFavorite}>Favorite</button>) }
</>) : (
this.fetchContent(contentID)
)}
</Grid.Row>
</Grid.Column>
<Grid.Column></Grid.Column>
<Grid.Column stretched textAlign='left' width={3}>
<Grid.Row stretched style={{height: '4%'}}>
</Grid.Row>
<Grid.Row stretched style={{height: '96%'}}>
<h3>Next video up:</h3>
{this.state.sideBarContent.length > 0 ? (
<Card.Group fluid itemsPerRow={1}>
{contentArr}
</Card.Group>
) : (this.fetchSidebarContent())}
</Grid.Row>
</Grid.Column>
</Grid.Row>
</Grid>
)
}
}
VideoPlayer组件:
import React from 'react'
export default class VideoPlayer extends React.Component {
render() {
return(
<div>
<video width="720" height="480" controls controlsList="nodownload" autoPlay>
<source src={this.props.src} type="video/mp4" />
Your browser does not support the video tag
</video>
</div>
)
}
}
请告诉我您是否需要查看其他代码。
答案 0 :(得分:0)
不切换视频的原因是因为视频的数据是在componentDidMount
上获取的。当安装组件时,此lyfecycle挂钩仅在组件生存期内执行一次。要检测其道具的变化,您应该像这样使用componentDidUpdate
:
componentDidUpdate(prevState, prevState) {
// Detect if the video id has changed
const contentID = this.props.props.location.pathname.split('/')[2]
if (contentID !== prevState.contentID) {
this.props.getUser()
.then(this.fetchContent(contentID))
.then(this.fetchSidebarContent())
// Update the state
.then(this.setState({ contentID }))
}
}
然后将URL绑定到video
元素本身,而不是使用source
元素(基于this post):
VideoPlayer
:
<video width="720" height="480" src={this.props.src} controls controlsList="nodownload" autoPlay>