As the title says, I have a homepage which uses a map() function to map through an arrayList which holds the information about songs, like title, artist, songURL and img.
When I map() through it I will have many "songs" like you would have with blog posts. many elements which is an article which shares the same classname.
Within this map() function I assign a component to each object mapped which is called , this component renders waveforms etc.. the audiovisualizer component also have a button inside for Play/Pause features. and this is the button I want to interact with the Homepage.
When this button is clicked, I want to change the classname for this specific element.
Through useState and callback functions, I got it almost working, but instead of changing the classname for the specific elements that is related to the button clicked, ALL of the "elements/songs" where changed, and not the one targeted.
I will show you the code down under, so you can see the "Tree" and get an understanding of the code.
My result, would be that the button that is attached to each "song" element, would update that specific parent/grandparent element sit sits inside of. but I can't really seem to wrap my head around the logic.
Im completely new to react, this is my first project ever, so go easy on me.
There is also pictures to see what what the code is doing. My goal is to make the specific play/pause object to have an CSS class that will pull up that song and have a position so you can't scroll while its playing. I want to add an pseudo-element to change background color so you can only see that specific card from the list of cards.. from the picture you can see 2 songs. when I click the play/pause I want that card to get an absolute background that will cover the other song.. Problem is that when I try to onClick={} the button that is nested, I can't reach the event.target... and if I do, all of the are changed, not the specific parent element that holds the button.
EDIT - SOLVED solved the entire problem by referencing the button using useRef. then I used that element like this let buttonRef = buttonRef.current.closest("my wanted parent by classname").classname, and then I changed that manually.
CODE:
Home.js ** this is where the songs/cards are made swith the map() function // be aware, I removed unrelated code for easier view.. **
const Home = (props) => {
const [songs, setSongs] = useState([]);
return (
<div className='home_wrapper'>
<>
{loading ?
<ClipLoader color="#36d7b7" />
:
<div className='homepage_container'>
<h1 className='homeTitleSongs'>Songs</h1>
<button className='logOutButton' onClick={handleLogout}>Logout</button>
{/* // Map through our song library and display all items on homepage */}
{ songs.map((data) => {
return (
// I WANT TP TARGET THE <Article> element´s classname and edit this when the button from inside <AudioVisualizer> component gets clicked.
// Problem is that this is a map function, so when i did get to change it, it changed ALL of the elements from the map function, not the one specific
// where the button is attached to.
<article key={data.id} className='card'>
<div className='card_content'>
<img className='card_image' src={data.image} alt=""/>
<div className='song_info'>
<h2>{data.title}</h2>
<h4>{data.artist}</h4>
</div>
<div className='audio_wrapper'>
<AudioVisualizer audio={data.audio}/>
</div>
</div>
</article>
)
})}
</div>
}
</>
</div>
)
}
export default Home
audioVisualizer component::
const AudioVisualizer = (props) => {
const [isPlaying, setIsPlaying] = useState(false)
const [volume, setVolume] = useState(0.5);
const playButton = faCirclePlay;
const pauseButton = faCirclePause;
const audioRef = useRef(null);
const audioTrackRef= useRef(undefined);
// Create audio waveform object, and load song from database..
useEffect(()=>{
if (audioRef.current){
audioTrackRef.current = wavesurfer.create({
container: audioRef.current,
progressColor: "#13AEA2",
waveColor: "red",
cursorColor: "OrangeRed",
preload: true,
backend: "WebAudio", // originally = "MediaElement"
barWidth: 2,
barHeight: 1, // the height of the wave
fillParent: true,
hideScrollbar: true,
responsive: true,
});
audioTrackRef.current.load(props.audio);
}
}, [])
// Handle play pause button
const handlePlayPause = (e) => {
// Get a view of what the "click" registers:
// if playing == pause
if ( ! isPlaying ) {
console.log("not playing.. Start playing");
audioTrackRef.current.play()
setIsPlaying(isClicked => true)
return
}
else {
console.log("Is playing.. will pause")
audioTrackRef.current.pause()
setIsPlaying(isClicked => false);
return
}
};
return (
<>
<div className='audio' ref={audioRef}>
</div>
<div className='audioKnobs'>
// This is the button i click for play pause a song inside a specific "song" card. and this card is the one i want to update the classname of..
<button className="playpausewrapper" onClick={handlePlayPause}>
<FontAwesomeIcon className={ isPlaying ? 'playButton activeButton' : 'playButton notActiveButton'} icon={ isPlaying ? pauseButton : playButton} />
</button>
<input type="range" className='VolumeSlider onPhoneRemoveVolumeSlider' id="volume" name="volume" min="0.01" max="1" step=".025" onChange={onVolumeChange} defaultValue={volume}/>
</div>
</>
)
}
export default AudioVisualizer;