简体   繁体   English

React:如何在钩子中添加 state 更改事件侦听器?

[英]React: How to add state changing event listeners in hooks?

I am working on a little music component that I found online.我正在研究我在网上找到的一个小音乐组件。 Currently now it works fine, but I have tried to make en event listener that toggles a state variable whenever the audio component is playing or no.目前它工作正常,但我试图让 en 事件监听器在音频组件播放或不播放时切换 state 变量。

Currently I toggle this variable manually, whenever the user clicks a button.目前,每当用户单击按钮时,我都会手动切换此变量。 But if the user is toggling using play/pause buttons on the keyboard, the state variable for "isPlaying" doesn't change unless I toggle it on the onplay and onpause event listeners.但是,如果用户使用键盘上的播放/暂停按钮进行切换,则“isPlaying”的 state 变量不会改变,除非我在onplayonpause事件侦听器上切换它。

Unfortunately, this breaks the entire functionality for the hook, and I am nor sure what to do in order to solve it..不幸的是,这破坏了钩子的整个功能,我不确定该怎么做才能解决它。

Codesandbox here: https://codesandbox.io/s/freaking-music-player-ldxde?file=/src/hooks/useMusicPlayer.js此处的代码沙盒: https://codesandbox.io/s/freaking-music-player-ldxde?file=/src/hooks/useMusicPlayer.js

This is the part that breaks it: [src/hooks/useMusicPlayer.js - line: 7]这是破坏它的部分:[src/hooks/useMusicPlayer.js - line: 7]

useEffect(() => {
    if (state.audioPlayer) {
      //  => Applying these event listeners **** up everything!
      // console.log(state.audioPlayer);
      //   state.audioPlayer.onplay = (event) => {
      //     setState((state) => ({ ...state, isPlaying: true }));
      //   };
      //   state.audioPlayer.onpause = (event) => {
      //     setState((state) => ({ ...state, isPlaying: false }));
      //   };
      state.audioPlayer.onended = event => {
        playNextTrack();
      };
    }
  }, [state, playNextTrack]);

The onended event works fine.. No trouble whatsoever.. But the other ones are messing up the experience. onended事件运行良好.. 没有任何问题.. 但其他事件正在破坏体验。

UPDATE: Moving setState out of useEffect更新:将setState移出useEffect

Adding this method:添加此方法:

  function togglePause() {
    setState((state) => ({
      ...state,
      isPlaying: state.audioPlayer ? !state.audioPlayer.paused : false,
    }));
  }

And updating the useEffect并更新useEffect

  useEffect(() => {
    if (state.audioPlayer) {
      console.log(state.audioPlayer);
      state.audioPlayer.onplay = (event: Event) => {
        togglePause();
      };
      state.audioPlayer.onpause = (event: Event) => {
        togglePause();
      };
      state.audioPlayer.onended = (event: Event) => {
        playNextTrack();
      };
    }
  }, [state, playNextTrack]);

This however still causes issues..然而,这仍然会导致问题..

Clarification on the actual issue itself澄清实际问题本身

Once the first state.audioPlayer has ended , the event listeners aren't transferred to the next Audio Component, whereas by NOT having the onplay and onpause listeners written in useEffect , the onended is indeed created anew and it works..一旦第一个state.audioPlayer ended ,事件侦听器不会转移到下一个音频组件,而通过没有useEffect中编写onplayonpause侦听器,确实会重新创建onended并且它可以工作。

There wasn't an actual issue with the code itself.代码本身没有实际问题。 It boils down to the various event handlers.它归结为各种事件处理程序。 The onpause event is implicitly triggered by the onended which caused multiple state changes to happen in the same event. onpause事件由onended隐式触发,导致多个 state 更改发生在同一事件中。

The codesandbox is now fully working. 代码沙盒现在可以正常工作了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM