React项目:播放列表增删曲目后总时长不更新问题求助
问题:React播放列表总时长动态计算功能无响应排查
背景
我是React新手,正在Codecademy Pro「全栈工程师」路径中完成第一个完整项目:基于Spotify API开发React网站,实现获取曲目并创建播放列表保存至Spotify的功能。
我希望在App→Playlist组件中添加播放列表总时长动态计算功能:每次添加或移除曲目时,总时长自动更新。目前已完成以下工作:
- 在Spotify.js中获取了
duration_ms数据 - 在Playlist.js中实现了单首歌曲时长(分钟格式)的展示
- 在App.js中通过
useState定义了totalTime和setTotalTime,默认值为'0:0' - 将相关props从App.js传递到Playlist.js,再传递给新建的Time函数组件
问题
在Time.js中,我渲染了展示totalTime的HTML元素,并使用useCallback定义了一个更新totalTime状态的函数,该函数应在播放列表tracks状态变化时触发。但目前功能无响应!DevTools显示tracks已传入Time组件,且函数单独传入硬编码参数测试有效,怀疑问题出在props命名上。
相关代码
App.js
import React, { useState, useCallback, useEffect } from "react"; import "./App.css"; import Playlist from "../Playlist/Playlist"; import SearchBar from "../SearchBar/SearchBar"; import SearchResults from "../SearchResults/SearchResults"; import Spotify from "../../util/Spotify"; const App = () => { const [searchResults, setSearchResults] = useState([]); const [playlistName, setPlaylistName] = useState("New Playlist"); const [playlistTracks, setPlaylistTracks] = useState([]); const [totalTime, setTotalTime] = useState(0+':'+0); const search = useCallback((term) => { Spotify.search(term).then(setSearchResults); }, []); const addTrack = useCallback( (track) => { if (playlistTracks.some((savedTrack) => savedTrack.id === track.id)) return; setPlaylistTracks((prevTracks) => [...prevTracks, track]); }, [playlistTracks] ); const removeTrack = useCallback((track) => { setPlaylistTracks((prevTracks) => prevTracks.filter((currentTrack) => currentTrack.id !== track.id) ); }, []); const updatePlaylistName = useCallback((name) => { setPlaylistName(name); }, []); const savePlaylist = useCallback(() => { const trackUris = playlistTracks.map((track) => track.uri); Spotify.savePlaylist(playlistName, trackUris).then(() => { setPlaylistName("New Playlist"); setPlaylistTracks([]); }); }, [playlistName, playlistTracks]); return ( <div> <h1> Ja<span className="highlight">mmm</span>ing </h1> <div className="App"> <SearchBar onSearch={search} /> <div className="App-playlist"> <SearchResults searchResults={searchResults} onAdd={addTrack} /> <Playlist playlistName={playlistName} playlistTracks={playlistTracks} onNameChange={updatePlaylistName} onRemove={removeTrack} onSave={savePlaylist} totalTime={totalTime} handleTime = {setTotalTime} /> </div> </div> </div> ); }; export default App;
Playlist.js
import React, { useCallback, useEffect } from "react"; import "./Playlist.css"; import TrackList from "../TrackList/TrackList"; import Time from "../Time/Time"; const Playlist = (props) => { const handleNameChange = useCallback( (event) => { props.onNameChange(event.target.value); }, [props.onNameChange] ); return ( <div className="Playlist"> <input onChange={handleNameChange} defaultValue="New Playlist" /> <TrackList tracks={props.playlistTracks} isRemoval={true} onRemove={props.onRemove} /> <br/> <Time onChange={props.setTotalTime} totalTime={props.totalTime} tracks= {props.playlistTracks} /> <button className="Playlist-save" onClick={props.onSave}> SAVE TO SPOTIFY </button> </div> ); }; export default Playlist;
Time.js
import React, {useCallback} from "react"; const Time =(props) => { const handleTotalTime = useCallback(()=> { let totalTime = 0; props.tracks.forEach((track)=> { totalTime += track.duration_ms; }) const minutes = Math.floor(totalTime/60000); const seconds = ((totalTime % 60000) /1000).toFixed(0); let newTime = minutes + ':' + (seconds < 10 ? '0': '') + seconds; props.setTotalTime(newTime); }, [props.tracks]); return ( <span>Your Playlist Total Time is currently: <input value={props.totalTime} onChange={handleTotalTime} /></span> ); } export default Time;
问题修复方案
1. 修正Props传递的命名错误
- App.js中传给Playlist的更新函数是
handleTime={setTotalTime},但Playlist里传给Time时错误使用了props.setTotalTime,实际应该是props.handleTime - Time组件接收的props名也需要对应调整,避免不匹配
2. 修正触发逻辑
原来把计算函数绑定在input的onChange事件上,只会在用户手动修改输入框时触发,正确的做法是用useEffect监听tracks数组的变化,自动执行计算。
修复后的代码
修正Playlist.js中的Time组件props
// 原代码 <Time onChange={props.setTotalTime} totalTime={props.totalTime} tracks= {props.playlistTracks} /> // 修改后 <Time setTotalTime={props.handleTime} totalTime={props.totalTime} tracks={props.playlistTracks} />
重写Time.js的计算逻辑
import React, { useEffect } from "react"; const Time = (props) => { useEffect(() => { let totalTimeMs = 0; props.tracks.forEach((track) => { totalTimeMs += track.duration_ms; }); const minutes = Math.floor(totalTimeMs / 60000); const seconds = ((totalTimeMs % 60000) / 1000).toFixed(0); const newTime = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; props.setTotalTime(newTime); }, [props.tracks, props.setTotalTime]); return ( <span>Your Playlist Total Time is currently: {props.totalTime}</span> ); }; export default Time;
额外优化
- 总时长是计算得出的只读值,不需要用input展示,直接用文本渲染即可
- App.js中
totalTime的初始值可以改为'0:00',格式更统一
内容的提问来源于stack exchange,提问作者Marie
相关产品推荐
相关产品推荐

