首页 > 解决方案 > React 播放列表中改变歌曲,useEffect hook 依赖数组

问题描述

问题描述

我正在使用Soundcloud API制作播放列表播放器,但在单击下一首/上一首按钮以切换到下一首歌曲时遇到问题。使用钩子成功获取了初始歌曲,但是当在下一个/上一个按钮中执行方法useEffect时,我不知道如何再次调用此钩子。onClick()

目前,播放/暂停按钮可以正常工作,但下一个/上一个按钮只能在涉及 { play/pause/previous/next } 按钮的某些特定点击序列下工作。考虑到我的 useEffect 钩子似乎是错误的,这是可以预料的。

JSFiddle(无法插入 Stackoverflow JS/HTML/CSS widjet)

[-------- 在这里工作 JSFiddle !!---------]

播放列表.tsx

import react, { useState, useEffect } from 'react';
const SC = require('soundcloud');

SC.initialize({
  client_id: '1dff55bf515582dc759594dac5ba46e9'
});

const playlist = [
    913128502,
    755552476,
    604329399
]

const playIcon = 'https://www.pngfind.com/pngs/m/20-201074_play-button-png-image-background- 
circle-transparent-png.png';
const pauseIcon = 'https://thumbs.dreamstime.com/z/pause-button-icon-transparent-background- 
sign-flat-style-204042531.jpg';
const prevIcon = 'https://i.postimg.cc/xCry8pgt/prev2.png';
const nextIcon = 'https://i.postimg.cc/ncwmMwhB/next.png';

const musicFetch = (trackId) => {
   return SC.stream('/tracks/' + trackId)
     .then(track => {
        return track;
   })
}    

const Playlist = () => {
   const [playState, setPlayState] = useState(false);
   const [track, setTrack] = useState<any>(null);
   const [playlistIndex, setPlaylistIndex] = useState(0);
  


    // use effect that fetches the initial song upong first render
    useEffect(() => {
        musicFetch(playlist[playlistIndex]).then((music) => {
          music.setVolume(0.025); //increase if you don't hear background sound
          setTrack(music);
        });
    }, [])
 
    // use effect that should fetch new song upon clicking next or previous button
    useEffect(() => {
        musicFetch(playlist[playlistIndex]).then((music) => {
          music.setVolume(0.2); //increase if you don't hear background sound
          setTrack(music);
        });
    }, [setPlayState, playlistIndex])
  
    const handleClick = async (direction) => {
        direction === 'play' ? await enableMusic() : await changeMusic(direction);
    }
 
    const enableMusic = async () => {
        if (track) {
            setPlayState(!playState);
            playState ? await track.pause() : await track.play();
        }
    }
 
    const changeMusic = async (direction) => {
        setPlaylistIndex(
            direction === 'next' ? await playlistIndex+1 : await playlistIndex-1
        );
    }
    return (
        <div>
           <img src={prevIcon} 
                onClick={() => { handleClick('prev') }}
                height="100" width="100"/>
           <img src={!playState ? playIcon : pauseIcon } 
                onClick={() => { handleClick('play') }}
                height="100" width="100" >
           </img>
           <img src={nextIcon}
                onClick={() => { handleClick('next') }}
                height="100" width="100"/>
        </div>
    )
}

export default Playlist;

我尝试过的事情

我已阅读有关useEffect钩子条件依赖数组的信息,并尝试在我的 useEffect 钩子中设置任何涉及setPlaylistindex, playlistIndex,的组合setTrack,但没有成功。我已经考虑过这个useCallback钩子,但这似乎不是正确的解决方案。

我试图找到一种卸载和挂载的方法,以便根据请求调用空依赖 useEffect 挂钩,我能够为此设计一个forceUpdate(),但这也不能解决问题。

有谁知道我该如何解决这个问题?

标签: reactjsajaxuse-effect

解决方案


您需要useEffect正确连接挂钩中的依赖项。

有单独useEffect的钩子来捕捉播放/暂停和播放列表索引状态的变化。您可以将依赖项添加trackuseEffect处理播放/暂停状态更改的挂钩并删除任何其他useEffect挂钩,包括具有空依赖项列表的挂钩。

React.useEffect(async () => {
    const music = await musicFetch(playlist[playlistIndex]);
    music.setVolume(0.2);
    setTrack(music);
 }, [playlistIndex]);
 
 React.useEffect(async ()=>{
    playState ? await track.play() : await track.pause();
 }, [track, playState]);

然后,您可以enableMusic按如下方式重构方法

 const enableMusic = async () => {
        if (track) {
        setPlayState(!playState);
    }
 }

推荐阅读