I've created a music player and I'm trying to add a function that adds a song to the audio player component when the song image is clicked.
I've used the createContext hook to access my state value globally as it makes it easier to pass my values.
As seen in the code below, I have an onClick function in the SongGrid component that gets the song file and stores it in the songClicked state. This state value is then accessed in my MusicPlayer component through the createContext hook.
When I view the createContext hook in the console, It shows that the songClicked value has updated to the songFile that I was referencing.
After doing this, I then set the currentSong value (which updates audio player source file) to my songClicked state which should then play the song file.
Does anyone know why the song will still not play? Is there something I'm missing? I'll simplify the source code to make it more readable.
// Context.js file which is imported into files.
import { createContext } from "react";
export const songContext = createContext({});
// Music.js file with songs that are passed as a prop into the SongGrid component.
import DrakeOneDance from '../music/Drake_One_Dance.mp3'
import AdelleHello from '../music/Adele_Hello.mp3'
import JuiceWrldLucidDreams from '../music/Lucid_Dreams.mp3'
import KingsOfLeonPyro from '../music/Pyro.mp3'
<div className='music-container'>
<SongGrid songs={songs} />
</div>
import React, { useState } from 'react';
import { useContext } from 'react';
import {songContext} from '../pages/Context'
function SongGrid({songs}) {
const { songClicked, setSongClicked } = useContext(songContext)
function getSongOne() {
let songFile = songs.map(song => song.songFile)
setSongClicked(songFile[0]) // Grabs the first song file in the songs array
}
return (
<div className="song-main-container">
<img src={Rap} onClick={getSongOne} />
</div>
)
}
export default SongGrid
import React, { useState, useEffect, useRef } from 'react'
import {songContext} from '../pages/Context'
import { useContext } from 'react';
function MusicPlayer({songs}) {
// References audio player tag to update source file.
const audioPlayer = useRef()
//State
const { songClicked, setSongClicked } = useContext(songContext)
const [currentSong] = useState(songClicked); // This should update audio src file?
const [isPlaying, setisPlaying] = useState(false);
function togglePlay() {
if(!isPlaying) {
audioPlayer.current.play()
} else {
audioPlayer.current.pause()
}
setisPlaying(isPlaying => !isPlaying)
}
return (
<div className='music-player-container'>
<audio src={currentSong} ref={audioPlayer} muted={mute} />
</div>
)
}
export default MusicPlayer
CodePudding user response:
The currentSong
state in your MusicPlayer component is not being updated when songClicked
changes.
You correctly set the initial state of currentSong using const [currentSong] = useState(songClicked);
however subsequent changes will not be set.
To do this, you have to make use of useEffect
in your MusicPlayer component, like so:
function MusicPlayer({songs}) {
...
const { songClicked, setSongClicked } = useContext(songContext)
const [currentSong, setCurrentSong] = useState(songClicked); // This should update audio src file?
...
useEffect(() => {
setCurrentSong(songClicked)
if (songClicked) {
audioPlayer.current.play()
}
}, [songClicked])
return (
<div className='music-player-container'>
<audio src={currentSong} ref={audioPlayer} muted={mute} />
</div>
)
}
export default MusicPlayer
I would however question why you need to hold your state in both the SongContext and the MusicPlayer. If songClicked
is always going to be the same as currentSong
, then I would remove currentSong
altogether and just supply songClicked
to your audio element.
...
<audio src={songClicked} ref={audioPlayer} muted={mute} />
...