1

I am making an page that is to be used to show some internal videos in my company. There are five short videos so I thought of making the video player on the left, and a playlist on the right, kind of like how YouTube does it.

However, I want to be able to click a video on the right and then the video on the left side will change accordingly, along with some meta data (title and description) under the video player.

What I want to achieve is when a Playlist component item is click, this should propagate up to parent component and down to the Video component.

Currently my code looks like this:

const videos = [{
    'title' => 'Lorem ipsum',
    'short_desc' => '',
    'long_desc' => '',
    'url' => 'videofile.mp4',
    'thumbnail' => 'thumb.jpg',
    'length': 55
},{
    'title' => 'Lorem ipsum 2',
    'short_desc' => '',
    'long_desc' => '',
    'url' => 'videofile2.mp4',
    'thumbnail' => 'thumb2.jpg',
    'length': 72
}];

class App extends Component {
    constructor() {
        super();

        this.state = {
            videos: videos,
            source: videos[0]
        }
    }

    changeVideo(video) {
        // Some logig for changing video
    }

    render() {
        let playlist = this.state.videos.map((video, index) => <Playlist key={shortid.generate()} details={video} changeVideo={this.changeVideo.bind(this)} />)

        let video = <Video ref="player" source={this.state.source} />

        return(
            <div className="app">
                <section className="left">
                    {video}
                </section>
                <section className="right">
                    {playlist}
                </section>
            </div>
        )
    }
}

class Playlist extends Component {
    handleClick(e) {
        this.props.changeVideo(this);
    }

    render() {
        let {title, length, short_desc, long_desc, thumbnail} = this.props.details;
        return(
            <div className="playlistItem" onClick={this.handleClick.bind(this)}>
                <img src={thumbnail} />
                {title}
                {short_desc} ({length})
            </div>
        )
    }
}

class Video extends Component {
    changeVideo(video) {
        // change video
    }

    render() {
        return {
            <section className="playerArea">
                <Player
                    ref="player"
                    poster={this.props.source.thumbnail}
                    src={this.props.source.url}>
                    <LoadingSpinner />
                    <BigPlayButton position="center" />
                </Player>
                <h1>{this.props.source.title}</h1>
                <p>{this.props.source.long_desc}</p>
            </section>
        }
    }
}

The video player I am using is the video-reactjs package.

rebellion
  • 6,628
  • 11
  • 48
  • 79

1 Answers1

1

In App:

constructor(props) {
  ...
  this.changeVideo = this.changeVideo.bind(this);
}

changeVideo(index) {
  this.setState({ source: this.state.videos[index] });
}

render() {
  let playlist = this.state.videos.map((video, index) => {
     <Playlist key={index} 
               details={video} 
               changeVideo={this.changeVideo.bind(null, index)} />
  })
  ...remaining code...

In Playlist:

class Playlist extends Component {
  render() {
    let {title, length, short_desc, long_desc, thumbnail} = this.props.details;
    return(
        <div className="playlistItem" onClick={this.props.changeVideo}>
            <img src={thumbnail} />
            {title}
            {short_desc} ({length})
        </div>
    );
  }
}

Edit: alternative solution, with explicit binding of changeVideo.

chris Frisina
  • 19,086
  • 22
  • 87
  • 167
Thomas Hennes
  • 9,023
  • 3
  • 27
  • 36
  • Thanks for answering! I get an unexpected token error in "const changeVideo" where it reacts to the constant name. I should mention that I use facebookincubator/create-react-app as boilerplate code, if that may have anything to do with the issue. – rebellion Oct 12 '17 at 08:20
  • Will amend answer to use alternative, more explicit approach. – Thomas Hennes Oct 12 '17 at 08:22
  • Answer amended, notice the additional instruction in the constructor, and the change in the way `changeVideo` is declared. Let me know how this works. – Thomas Hennes Oct 12 '17 at 08:27
  • You're welcome Ronny. I also realised I didn't give much explanation with my answer. Are you good with the whole concept of binding the index directly to the event handler passed as a prop, or do you want me to elaborate on this? – Thomas Hennes Oct 12 '17 at 08:41
  • If you want to give a more thorough explanation I will be happy! – rebellion Oct 12 '17 at 09:02
  • Because of issues with IE11, I had to switch to use the Video.js library directly, and not the React one, and I am almost back to square one. Are you able to do a quick helping session Jaxx ? – rebellion Oct 16 '17 at 08:51
  • @Ronny-AndréBendiksen I'd gladly help, but my knowledge lies with React, I have zero experience with Video.js. – Thomas Hennes Oct 16 '17 at 09:19
  • I understand. I think I need to rethink how I would solve this. I want to store the videojs player object in the state, however I says that videojs methods isn't available. – rebellion Oct 16 '17 at 10:03