I’m building a music player in React, and I’m trying to update the track title and artist dynamically using useEffect when the props (title, artist) change. However, while the values update correctly in the console log, they do not reflect in the DOM.
I am using state hooks (useState) for the title and artist, and I’ve ensured that the component should re-render when these states change. Despite this, the DOM still doesn’t update with the new values.
import React, { useEffect, useState } from 'react';
import { FaBackward, FaPlay, FaPause, FaForward, FaHeart, FaRandom, FaVolumeUp } from 'react-icons/fa';
import useAudio from '../Audio/useAudio';
import api from '../../Services/api';
const Playbar = ({ url, title, artist, id }) => {
//url is the audio url
//title is the title of the track
//artist is the artist of the song
//id is the id of the track
const [playing, toggle] = useAudio(url);
const [titles, setTitles] = useState(title || "");
const [artists, setArtists] = useState(artist || "");
// Update titles and artists when props change
useEffect(() => {
setTitles(title || "");
setArtists(artist || "");
}, [title, artist]);
// Update current playing track in the database if playing is true and the track has changed
useEffect(() => {
if (playing) {
api.post(`/api/currentplaying`, {
playing: playing,
title: titles,
artist: artists,
id: id
});
}
}, [titles, artists, playing, id]);
// Fetch current playing track from the database
useEffect(() => {
const fetchCurrentPlaying = async () => {
try {
const res = await api.get(`/api/fetchcurrentplaying/${id}`);
if (res.data.current && res.data.current.length > 0) {
const currentTrack = res.data.current[0];
setTitles(currentTrack.title);
setArtists(currentTrack.artist);
} else {
console.log("No current playing data found.");
}
} catch (error) {
console.error('Error fetching current playing:', error);
}
};
fetchCurrentPlaying();
}, [id]);
// Log when the playbar is updated
useEffect(() => {
console.log("Playbar updated with:", { url, title, artist });
}, [url, title, artist]);
return (
<footer className="fixed text-white bottom-0 left-0 right-0 bg-gray-800 p-2 flex items-center">
<div className="flex items-center">
<img src="https://placehold.co/50x50" alt="Current song" className="rounded-full mr-4" />
<div>
<p className="font-bold">{titles || "No Title"}</p>
{console.log("Title", titles)}
{console.log("Artist", artists)}
<p>{artists || "No Artist"}</p>
</div>
</div>
<div className="flex-1 flex justify-center items-center">
<FaBackward className="mx-4" />
{playing ? (
<FaPause className="mx-4" onClick={toggle} />
) : (
<FaPlay className="mx-4 " onClick={toggle} />
)}
<FaForward className="mx-4" />
</div>
<div className="flex items-center">
<FaHeart className="mx-4" />
<FaRandom className="mx-4" />
<FaVolumeUp className="mx-4" />
</div>
</footer>
);
}
export default Playbar;
Problem:
The title and artist props are passed into the Playbar component, and the state variables titles and artists are updated accordingly inside a useEffect.
These state variables log correctly in the console (console.log), but the DOM is not reflecting the updated state values.
I’ve confirmed that the state is being updated in Console, but it doesn’t re-render the DOM as expected.
What I’ve tried:
I’ve used useEffect to update the state values when the props change.
I’m ensuring that setTitles and setArtists are called correctly.
I’m using React.memo for the Playbar component, but the issue persists.
Can anyone help me identify why the updated state values are not reflected in the DOM even though they are correctly logged?
useAudio.js
import { useState, useEffect } from 'react';
const useAudio = (url) => {
const = useState(new Audio(url));
const [playing, setPlaying] = useState(false);
const toggle = () => {
setPlaying(prev => !prev);
};
useEffect(() => {
const handleEnded = () => setPlaying(false);
audio.addEventListener('ended', handleEnded);
return () => {
audio.pause();
audio.removeEventListener('ended', handleEnded);
};
}, );
useEffect(() => {
if (url && url !== undefined) {
const newAudio = new Audio(url);
setAudio(newAudio);
audio.src = url;
setPlaying(true);
}else{
setPlaying(false);
}
}, [url]);
useEffect(() => {
if (playing && url) {
audio.play().catch(error => {
console.error("Error playing audio:", error);
});
} else {
audio.pause();
}
}, [playing, audio]);
return [playing, toggle];
};
export default useAudio;