内容未从react-router链接加载

时间:2019-03-17 10:06:57

标签: javascript html reactjs react-router

我正在将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>
      )
  }
}

请告诉我您是否需要查看其他代码。

1 个答案:

答案 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>