React音乐播放器组件接收歌曲对象数组无法播放求助
问题:传入歌曲对象数组后音乐播放器无法播放
我开发了一个MusicPlayer组件,之前直接传入mp3文件数组时可以正常播放,但改成传入包含歌曲信息的对象数组后功能失效,怀疑是props接收和解构的问题。
相关代码
Music组件(父组件)
import React from 'react' //Components import MusicPlayer from '../components/MusicPlayer'; //Song Images import Drake from '../images/Drake.jpg' import Adelle from '../images/adelle.png' import Elvis from '../images/Elvis_hounddog.jpg' //Song files import DrakeOneDance from '../music/Drake_One_Dance.mp3' import AdelleHello from '../music/Adele_Hello.mp3' import ElvisHoundDog from '../music/Elvis.mp3' //Song array const songs = [ { artist: 'Drake', songName: 'One Dance', poster: Drake, songFile: DrakeOneDance }, { artist: 'Adelle', songName: 'Hello', poster: Adelle, songFile: AdelleHello }, { artist: 'Elvis', songName: 'Hound Dog', poster: Elvis, songFile: ElvisHoundDog }, ] function Music() { return ( <div className='music-container'> <MusicPlayer songs={songs}/> </div> ); } export default Music
MusicPlayer组件(子组件)
import React, { useState, useEffect, useRef } from 'react' // MUI ICONS import { Slider } from '@mui/material'; import SkipPreviousIcon from '@mui/icons-material/SkipPrevious'; import SkipNextIcon from '@mui/icons-material/SkipNext'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import PauseIcon from '@mui/icons-material/Pause'; import VolumeDownIcon from '@mui/icons-material/VolumeDown'; import VolumeUpIcon from '@mui/icons-material/VolumeUp'; import VolumeOffIcon from '@mui/icons-material/VolumeOff'; import VolumeMuteIcon from '@mui/icons-material/VolumeMute'; import IconButton from '@mui/material/IconButton' function MusicPlayer({songs}) { //Song Files const songFiles = songs.songFile; //Hooks const audioPlayer = useRef() //State const [index, setIndex] = useState(0); const [currentSong] = useState(songFiles[index]); const [isPlaying, setisPlaying] = useState(false); const [volume, setVolume] = useState(30); const [mute, setMute] = useState(false); useEffect(() => { if(audioPlayer) { audioPlayer.current.volume = volume / 100; } }, [volume]); function togglePlay() { if(!isPlaying) { audioPlayer.current.play() } else { audioPlayer.current.pause() } setisPlaying(isPlaying => !isPlaying) } function toggleSkipForward() { if(index >= songFiles.length - 1) { setIndex(0); audioPlayer.current.src = songFiles[0]; audioPlayer.current.play(); } else { setIndex(prev => prev + 1); audioPlayer.current.src = songFiles[index + 1]; audioPlayer.current.play(); } } function toggleSkipBackward() { if(index > 0) { setIndex(prev => prev -1); audioPlayer.current.src = songFiles[index -1]; audioPlayer.current.play(); } } function VolumeBtns() { return mute ? <VolumeOffIcon sx={{color: 'lime', '&:hover': {color: 'white'}}} onClick={() => setMute(!mute)} /> : volume <= 20 ? <VolumeMuteIcon sx={{color: 'lime', '&:hover': {color: 'white'}}} onClick={() => setMute(!mute)} /> : volume <= 75 ? <VolumeDownIcon sx={{color: 'lime', '&:hover': {color: 'white'}}} onClick={() => setMute(!mute)} /> : <VolumeUpIcon sx={{color: 'lime', '&:hover': {color: 'white'}}} onClick={() => setMute(!mute)} /> } return ( <div className='music-player-container'> <audio src={currentSong} ref={audioPlayer} muted={mute} /> <div className="controls"> <div className="volume"> <IconButton> <VolumeBtns /> </IconButton> <Slider min={0} max={100} value={volume} onChange={(e,v) => setVolume(v)} defaultValue={50} sx={{ width: 100, color: 'success.main', margin: '20px', }} /> </div> <div className="control-panel"> <IconButton onClick={toggleSkipBackward}> <SkipPreviousIcon sx={{ margin: '10px', cursor: 'pointer', color: 'silver', '&:hover': {color: 'blue'} }} /> </IconButton> {!isPlaying ? <IconButton onClick={togglePlay}> <PlayArrowIcon sx={{ margin: '10px', cursor: 'pointer', color: 'silver', '&:hover': {color: 'blue'} }} /> </IconButton> : <IconButton onClick={togglePlay}> <PauseIcon sx={{ margin: '10px', cursor: 'pointer', color: 'silver', '&:hover': {color: 'blue'} }} /> </IconButton> } <IconButton onClick={toggleSkipForward}> <SkipNextIcon sx={{ margin: '10px', cursor: 'pointer', color: 'silver', '&:hover': {color: 'blue'} }} /> </IconButton> </div> </div> </div> ) } export default MusicPlayer
错误分析与修复方案
1. 错误提取歌曲文件数组
songs是对象数组,原代码中songs.songFile会返回undefined(数组本身没有songFile属性),需要从每个对象中提取:
// 错误写法 const songFiles = songs.songFile; // 正确写法 const songFiles = songs.map(song => song.songFile);
2. currentSong状态未同步index变化
原代码中currentSong仅在初始化时赋值,index变化时不会自动更新,建议直接通过index计算,无需单独状态:
// 移除原currentSong状态定义 // const [currentSong] = useState(songFiles[index]); // 在audio标签中直接使用 <audio src={songFiles[index]} ref={audioPlayer} muted={mute} />
3. 跳转函数边界逻辑优化
原toggleSkipBackward在index为0时无处理,添加循环到最后一首的逻辑,同时简化跳转计算:
function toggleSkipForward() { const nextIndex = (index + 1) % songFiles.length; setIndex(nextIndex); audioPlayer.current.src = songFiles[nextIndex]; audioPlayer.current.play(); } function toggleSkipBackward() { const prevIndex = (index - 1 + songFiles.length) % songFiles.length; setIndex(prevIndex); audioPlayer.current.src = songFiles[prevIndex]; audioPlayer.current.play(); }
4. useEffect依赖修正
原useEffect中判断audioPlayer存在,但应直接判断audioPlayer.current:
useEffect(() => { if(audioPlayer.current) { audioPlayer.current.volume = volume / 100; } }, [volume]);
内容的提问来源于stack exchange,提问作者Gavin Walsh
相关产品推荐
相关产品推荐

