【问题标题】:React js : Audio element's src is updating on setState but the audioRef is notReact js:音频元素的 src 在 setState 上更新,但 audioRef 没有
【发布时间】:2021-05-30 18:12:08
【问题描述】:

请帮助我!我正在使用上下文 API 将曲目传递给 MucsicPlayer。但每当我设置 setTracks 状态音频元素 src 更新但 audioRef.current 不更新。我检查了它,发现 audioRef.current =

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

【问题讨论】:

    标签: javascript reactjs audio ecmascript-6 react-hooks


    【解决方案1】:

    useRef 不会在每次渲染时重新初始化。

    所以它会和第一次初始化时一样。

    因此,每当您切换曲目时,您也必须更新 audioRef。

    更改您的 toPrevTracktoNextTrack

    const toPrevTrack = () => {
       const prevIndex = trackIndex - 1 < 0 ? tracks.length - 1 : trackIndex - 1;
       const { audioSrc } = tracks[prevIndex]
       audioRef.current = new Audio(audioSrc);
    }
    
    const toNextTrack = () => {
       const nextIndex = trackIndex < tracks.length - 1 ? trackIndex + 1 : 0;
       const { audioSrc } = tracks[nextIndex]
       audioRef.current = new Audio(audioSrc);
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-20
      • 2020-07-26
      • 1970-01-01
      • 1970-01-01
      • 2021-01-12
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 2019-01-28
      相关资源
      最近更新 更多