I have playerInstance variable on which I can call methods like togglePlay(). I wanna be able to call it’s methods from different components. I tried to do this which Context API but it only works for sharing properties, when I’m trying to call spotifyPlayer.togglePlay() it shows an error: spotifyPlayer.togglePlay is not a function. I guess that useState() only stores properties but then how am I supposed to share methods? Is even using Context API any good for this problem? I already use redux-toolkit for sharing data
SpotifyPlayerContext.jsx
import React, { createContext, useEffect, useState } from "react"
import { useSelector } from "react-redux"
export const SpotifyPlayerContext = createContext()
export const SpotifyPlayerProvider = ({ children }) => {
const user = useSelector((state) => state.user.value)
const [spotifyPlayer, setSpotifyPlayer] = useState()
useEffect(() => {
console.log(spotifyPlayer)
}, [spotifyPlayer])
const initSpotifyPlayer = () => {
const script = document.createElement("script")
script.src = "https://sdk.scdn.co/spotify-player.js"
script.async = true
document.body.appendChild(script)
window.onSpotifyWebPlaybackSDKReady = () => {
const playerInstance = new window.Spotify.Player({
name: "Figure Out The Lyrics",
getOAuthToken: (cb) => {
cb(user.token)
},
})
playerInstance.connect()
playerInstance.addListener("ready", ({ device_id }) => {
console.log("Device ID", device_id)
playerInstance.device_id = device_id
setSpotifyPlayer(playerInstance)
})
playerInstance.addListener("player_state_changed", (state) => {
console.log("player state changed", state)
playerInstance.playback = state
setSpotifyPlayer({ ...playerInstance })
console.log("instance", playerInstance)
})
}
}
const value = { spotifyPlayer, setSpotifyPlayer, initSpotifyPlayer }
return <SpotifyPlayerContext.Provider value={value}> {children} </SpotifyPlayerContext.Provider>
}
export default SpotifyPlayerContext
Player.jsx
import React, { useContext, useEffect, useState } from "react"
import { useDispatch, useSelector } from "react-redux"
import { Tooltip } from "react-tooltip"
import SpotifyPlayerContext from "../SpotifyPlayerContext"
const Player = ({ spotifyAPI }) => {
const { spotifyPlayer, setSpotifyPlayer } = useContext(SpotifyPlayerContext)
useEffect(() => {
if (!spotifyPlayer) return
if (!spotifyPlayer.playback) spotifyAPI.transferMyPlayback([spotifyPlayer.device_id])
console.log("useEffect in Player", spotifyPlayer)
}, [spotifyPlayer])
return spotifyPlayer?.playback ? (
<button onClick={() => {console.log("spotifyPlayer", spotifyPlayer);spotifyPlayer.togglePlay()}}>toggle</button>
) : (
<div>loading</div>
)
}
export default Player
2
Answers
Okay, I was able to make it work. Instead of creating playerInstance when the onSpotifyWebPlaybackSDKReady I created it even outside of the component and only assign the player to it. So now I get data from spotifyPlayer but I call methods on playerInstance. Maybe it's not perfect but it looks like it works for now.
Updated SpotifyPlayerContext.jsx
Updated Player.jsx
Why don’t you try creating method to call togglePlay in Provider and use it in your component? Doesn’t it work?