首页 > 解决方案 > React js:音频元素 src 正在 setState 上更新,但 audioRef 没有

问题描述

请帮我!我正在使用上下文 API 将曲目传递给 MucsicPlayer。但每当我设置setTracks状态音频元素 src 更新<audio preload="auto" src="001.mp3">但 audioRef.current 不更新。我检查了一下,看到了audioRef.current = <audio preload="auto" src(unknown)>。所以 ref src 不会更新。我应该怎么办。并且您能否给我一些想法,以便在 setTracks 状态更改时自动播放音频。

import React, { useState, useEffect, useRef, useContext } from 'react'
import { TrackContext } from '../../music/TrackContext'

const MusicPlayer = () => {

    const [tracks, setTracks] = useContext(TrackContext)
    console.log(tracks)
    // states
    const [trackIndex, setTrackIndex] = useState(0)
    console.log(trackIndex)
    const [trackProgress, setTrackProgress] = useState(0)
    const [isPlaying, setIsPlaying] = useState(false)
    // eslint-disable-next-line
    const [volume, setVolume] = useState(1)
    const { title, artist, image, audioSrc } = tracks[trackIndex]

    //refs
    const audio = new Audio(audioSrc)
    const audioRef = useRef(audio)
    const intervalRef = useRef()
    const isReady = useRef(false)
    console.log(audioRef.current)
    const { duration } = audioRef.current
    const toPrevTrack = () => {
        if (trackIndex - 1 < 0) {
            setTrackIndex(tracks.length - 1)
        } else {
            setTrackIndex(trackIndex - 1)
        }
    }

    const toNextTrack = () => {
        if (trackIndex < tracks.length - 1) {
            setTrackIndex(trackIndex + 1)
        } else {
            setTrackIndex(0)
        }
    }


    const startTimer = () => {
        clearInterval(intervalRef.current)

        intervalRef.current = setInterval(() => {
            if (audioRef.current.ended) {
                toNextTrack()
            } else {
                setTrackProgress(audioRef.current.currentTime);
            }
        }, [1000])
    }

    useEffect(() => {
        if (isPlaying) {
            audioRef.current.play()

            startTimer();
        } else {
            clearInterval(intervalRef.current)
            audioRef.current.pause()
        }
        // eslint-disable-next-line
    }, [isPlaying])

    useEffect(() => {
        return () => {
            audioRef.current.pause()
            clearInterval(intervalRef.current)
        }
    }, [])

    useEffect(() => {
        audioRef.current.play()
        audioRef.current = new Audio(audioSrc)
        setTrackProgress(audioRef.current.currentTime)

        if (isReady.current) {
            audioRef.current.play()
            setIsPlaying(true)
            startTimer()
        } else {
            isReady.current = true
        }
        // eslint-disable-next-line
    }, [trackIndex])
    const onScrub = (value) => {
        clearInterval(intervalRef.current)
        audioRef.current.currentTime = value
        setTrackProgress(audioRef.current.currentTime)
    }

    const onScrubEnd = () => {
        if (!isPlaying) {
            setIsPlaying(true);
        }
        startTimer();
    }

    const onScrubVolume = (value) => {
        audioRef.current.volume = value
        setVolume(audioRef.current.value)
    }

    function formatMinutes(sec) {
        return new Date(sec * 1000).toUTCString().split(" ")[4].substr(3, 8)
    }

    const currentPercentage = duration ? `${(trackProgress / duration) * 100}%` : '0%';
    const trackStyling = `-webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(${currentPercentage}, #fff), color-stop(${currentPercentage}, #777))`;

   
    return (
        <div className="player">
            <div className="left-block">
                <div className="art">
                    <img src={image} alt="" />
                </div>
                <div className="song-details">
                    <div className="song-name">{title}</div>
                    <div className="artist-name">
                        <a href="sa">{artist}</a>
                    </div>
                </div>
            </div>
            <div className="center-block">
                <div className="song-progress">
                    <div>{formatMinutes(audioRef.current.currentTime)}</div>
                    <input
                        value={trackProgress}
                        step="1"
                        min="1"
                        max={duration ? duration : `${duration}`}
                        onChange={(e) => onScrub(e.target.value)}
                        onMouseUp={onScrubEnd}
                        onKeyUp={onScrubEnd}
                        style={{ background: trackStyling }}
                        type="range" />
                    <div>{duration ? formatMinutes(duration) : "00:00"}</div>
                </div>
            </div>
      
                </div>
            </div>
        </div>
    )
}


export default MusicPlayer

标签: javascriptarraysreactjsaudioreact-hooks

解决方案


推荐阅读