Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue when using multiple players #18

Open
jmvallejo opened this issue Aug 31, 2018 · 7 comments
Open

Issue when using multiple players #18

jmvallejo opened this issue Aug 31, 2018 · 7 comments

Comments

@jmvallejo
Copy link

Hi, I'm using react-jPlayer for playing various items inside the same page. Basically I want each player to have its own state and I'm giving it an id based on the element that it will be playing, the first time I load the players it works well, but once I go to a different page where additional players are loaded I get an error from mapStateToProps where it's trying to get media from undefined, as if it was trying to access a player id that doesn't exist from the reducer.

Here's the error:
TypeError: Cannot read property 'media' of undefined at Function.mapStateToProps [as mapToProps] (jPlayerContainer.js:36)

image

I'm wrapping the player inside a component that has additional logic for loading the files, but basically I'm initializing with the corresponding id on componentWillMount.

@MartinDawson
Copy link
Contributor

Have you had a look at this?

https://github.com/jplayer/react-jPlayer-examples/tree/master/jPlayers/MultiplePlayers

@jmvallejo
Copy link
Author

Yes! that was useful at first but I'm suspecting my issue is because of the way I'm initializing the players. In the example you provide player states are initialized during import and they have known ids.

By looking at the jplayer code I think that initialization is not happening through a redux action but probably modifying the store directly, I think this may be causing issues when trying to display multiple instances with different ids.

What's strange is that the first time I do it it works, then I move to a different component that does the same and it breaks. I'm still looking at a solution but help is very appreciated :)

@MartinDawson
Copy link
Contributor

MartinDawson commented Aug 31, 2018 via email

@jmvallejo
Copy link
Author

jmvallejo commented Aug 31, 2018

Here's my code for the player:

AudioPlayer (Container):

import React, { Component } from 'react'
import { connect } from 'react-redux'
import AudioPlayerView from '../../../components/content/chat/AudioPlayer'
import { get as getRecording } from '../../../webapi/recordings'
import { getCurrentAccount } from '../../../stateapi/config'
import { actions, initializeOptions } from 'react-jplayer'

export class AudioPlayer extends Component {
  constructor (props) {
    super(props)
    this.state = {
      playerStarted: false,
      playerLoading: false
    }
  }

  componentWillMount () {
    const { id } = this.props
    const playerOptions = {
      id,
      media: {
        sources: {},
        free: true
      }
    }
    initializeOptions(playerOptions)
  }

  componentWillUnmount () {
    const { clearMedia } = this.props
    clearMedia && clearMedia()
  }

  _startPlayer = e => {
    const { playerStarted } = this.state
    if (playerStarted) {
      e && e.preventDefault()
      return
    }
    this.setState(
      {
        playerLoading: true
      },
      () => {
        const { id, apiBaseUrl, setMedia } = this.props
        getRecording(id).then(response => {
          this.setState({
            playerLoading: false,
            playerStarted: true
          })
          if (response.body && response.body.files) {
            const { files } = response.body
            const stateFiles = {}
            for (let fileType in files) {
              stateFiles[fileType] = apiBaseUrl + files[fileType]
            }
            setMedia(stateFiles)
          }
        })
      }
    )
  }

  render () {
    const { id, playerInitialized } = this.props
    const { playerStarted, playerLoading } = this.state
    return (
      <AudioPlayerView
        id={id}
        playerStarted={playerStarted}
        playerLoading={playerLoading}
        startPlayer={this._startPlayer}
        playerInitialized={[playerInitialized]}
      />
    )
  }
}

export function mapStateToProps (state, ownProps) {
  const { id } = ownProps
  const account = getCurrentAccount(state)
  const apiBaseUrl = `https://${account && account.server}:8002/api`
  const { jPlayers } = state
  const playerInitialized = !!(jPlayers[id] &&
    jPlayers[id].mediaSettings &&
    jPlayers[id].media &&
    jPlayers[id].media.sources)

  return {
    apiBaseUrl,
    playerInitialized
  }
}

export function mapDispatchToProps (dispatch, ownProps) {
  const { id } = ownProps
  return {
    setMedia: sources => {
      dispatch(actions.setMedia(id, { sources, free: true }))
      dispatch(actions.play(id))
    },
    clearMedia: () => {
      dispatch(actions.pause(id))
      dispatch(actions.clearMedia(id))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(AudioPlayer)

Component:

import React from 'react'
import Icon from '../../icons/Icon'
import classNames from 'classnames'
import JPlayer, {
  Gui,
  SeekBar,
  BufferBar,
  Audio,
  Play,
  PlayBar,
  Duration,
  CurrentTime,
  BrowserUnsupported
} from 'react-jplayer'

const AudioPlayer = ({
  id,
  playerStarted,
  startPlayer,
  playerLoading,
  isOld,
  playerInitialized
}) => {
  if (!playerInitialized) {
    return null
  }
  return (
    <JPlayer
      id={id}
      className={classNames('jp-sleek audio-player', { 'is-old': isOld })}
    >
      <Audio />
      <Gui>
        <div className='jp-controls jp-icon-controls' onClick={startPlayer}>
          <Play>
            <Icon name='play' />
            <Icon name='pause' />
          </Play>
          <div className='jp-progress'>
            <SeekBar>
              <BufferBar />
              {playerLoading && <div className='loading' />}
              <PlayBar />
            </SeekBar>
            {playerStarted &&
              <div className='audio-timestamp'>
                <CurrentTime />
                <Duration />
              </div>}
          </div>
        </div>
        <BrowserUnsupported />
      </Gui>
    </JPlayer>
  )
}

export default AudioPlayer

@jmvallejo
Copy link
Author

I guess JSX won't be properly parsed herre 😞

@kapilropani
Copy link

#18 (comment)
is it resolved? @jmvallejo

@jmvallejo
Copy link
Author

Nope, I stopped trying and implemented my own solution using a native player :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants