johnw188
johnw188

Reputation: 742

React.js + video element: set current play time from react props?

I just started working in react and this is an issue that I haven't seen a good solution to so far. The problem is that I want to set a video playing in a tag to a location when a user clicks a button.

The current solution I have is as follows:

componentDidUpdate(prevProps, prevState) {
    console.log("Updating to timestamp: " + this.props.timestamp);
    var timestamp = this.props.timestamp;
    if (timestamp != prevProps.timestamp) {
        React.findDOMNode(this.refs.theVideo).currentTime = timestamp;
    }
}

Problem is, this seems really hacky. Now I'm in this situation where the user could click the same button twice and nothing would happen, so I'm looking at adding more state to the component to ensure that case works correctly.

Is this the correct approach? Everything in react so far seems super logical, but this just doesn't quite feel right. Would this be a situation where you'd expose a method on the child to the parent?

Upvotes: 3

Views: 5724

Answers (1)

Michelle Tilley
Michelle Tilley

Reputation: 159105

You touched on one solution in your question—you could expose a method on the child that sets the timestamp. However, this is a very imperative API, and might not fit well with an app that is otherwise declarative.

In a recent project, I implemented something like this with a declarative API using componentWillReceiveProps, very similar to your own solution:

componentWillReceiveProps: function(props) {
  if (this.props.playing !== props.playing) {
    this.audio[props.playing ? "play" : "pause"]();
  }

  if (this.props.lastSeek !== props.lastSeek) {
    var start = props.start,
        offset = props.currentTime - start;
    this.audio.currentTime = offset / 1000;
  }
}

By comparing the property given to the component the last time it was rendered with the property given to it this time, we can determine that the audio clip time needs to be adjusted.

I think the best solution involves creating a special <Video> component with the sole job of hiding such an imperative API behind a declarative API; then, your application doesn't need to know about the imperative API. So, in your app, you might use

render() {
  // ...
  <Video url={...} timestamp={this.props.timestamp} />
}

You can learn more about this concept in this meetup talk: "Bridging Imperative APIs with Kinetophone" (around 7:04).

Upvotes: 3

Related Questions