joshwcomeau / use-sound

A React Hook for playing sound effects
MIT License
2.75k stars 98 forks source link

Hot-reloading crashes when using sprites #43

Open martinjuhasz opened 4 years ago

martinjuhasz commented 4 years ago

When using sprites, hot reloading does not work anymore. When react calls commitHookEffectListMount after hot reloading, this gets called in use-sound

React__default.useEffect(function () {
    if (sound) {
      sound.volume(volume);
      sound.rate(playbackRate);
    } // A weird bug means that including the `sound` here can trigger an
    // error on unmount, where the state loses track of the sprites??
    // No idea, but anyway I don't need to re-run this if only the `sound`
    // changes.
    // eslint-disable-next-line react-hooks/exhaustive-deps

  }, [volume, playbackRate]);

where sound.rate(playbackRate); fails in howler because self._sprite is undefined TypeError: self._sprite[sound._sprite] is undefined.

Your comment suggest you're already aware of this issue. This is more a inconvinience than anything serious, so i created this issue just to keep track of this bug.

drscottlobo commented 3 years ago

I think I am getting an error from the same underlying issue. When I hot reload using my next.js app, I get that error. But I also get a very similar error when doing something as simple as adjusting the volume:

 const [volume, setVolume] = useState(0.75);
    const [play, soundingNote] = useSound([pianoSoundsOgg, pianoSoundsMp3, pianoSoundsM4a], {
        sprite: pianoSoundData.sprite,
        volume: volume,
    });

    function handleChangeVolumeOnClick() {
       if (volume === .75) {
          setVolume(.25)
       }
    }
}

I get the following error:

Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading '0')

Call Stack Howl.rate node_modules/howler/dist/howler.js (1564:0) eval node_modules/use-sound/dist/use-sound.esm.js (129:0) invokePassiveEffectCreate node_modules/react-dom/cjs/react-dom.development.js (23487:0) HTMLUnknownElement.callCallback node_modules/react-dom/cjs/react-dom.development.js (3945:0) Object.invokeGuardedCallbackDev node_modules/react-dom/cjs/react-dom.development.js (3994:0) invokeGuardedCallback node_modules/react-dom/cjs/react-dom.development.js (4056:0) flushPassiveEffectsImpl node_modules/react-dom/cjs/react-dom.development.js (23574:0) unstable_runWithPriority node_modules/scheduler/cjs/scheduler.development.js (468:0) runWithPriority$1 node_modules/react-dom/cjs/react-dom.development.js (11276:0) flushPassiveEffects node_modules/react-dom/cjs/react-dom.development.js (23447:0) eval node_modules/react-dom/cjs/react-dom.development.js (23324:0) workLoop node_modules/scheduler/cjs/scheduler.development.js (417:0) flushWork node_modules/scheduler/cjs/scheduler.development.js (390:0) MessagePort.performWorkUntilDeadline node_modules/scheduler/cjs/scheduler.development.js (157:0)

drscottlobo commented 3 years ago

UPDATE:

I found a work around using the exposedData Howl object:

` const [volume, setVolume] = useState(0.75); const [play, exposedData] = useSound([pianoSoundsOgg, pianoSoundsMp3, pianoSoundsM4a], { sprite: pianoSoundData.sprite, volume: volume, });

function handleChangeVolumeOnClick() {
   if (volume === .75) {
      setVolume(.25)
      exposedData.sound.volume(.25)  // update howl object volume at the same time as state.
   }
}

} `

drscottlobo commented 3 years ago

Ps. Love this Hook by the way, thanks for all your work on it!

drscottlobo commented 2 years ago

Still hoping this bug might get a fix? It's a bummer to keep having to reload the page with every change since this bug prevents hot reloading.

rymdmetafor commented 1 year ago

UPDATE:

I found a work around using the exposedData Howl object:

` const [volume, setVolume] = useState(0.75); const [play, exposedData] = useSound([pianoSoundsOgg, pianoSoundsMp3, pianoSoundsM4a], { sprite: pianoSoundData.sprite, volume: volume, });

function handleChangeVolumeOnClick() {
   if (volume === .75) {
      setVolume(.25)
      exposedData.sound.volume(.25)  // update howl object volume at the same time as state.
   }
}

} `

what is "pianoSoundData.sprite" in your solution?

drscottlobo commented 1 year ago

That's the list of sprites in the JSON object for the audio data. You can use https://github.com/tonistiigi/audiosprite to generate the JSON file and the audio file for whatever audio you are using.

Here's an example:

{ "src": ["/audio/sounds.ogg", "/audio/sounds.m4a", "/audio/sounds.mp3", "/audio/sounds.ac3"], "sprite": { "guitar-A2#": [0, 2142.4036281179137], "guitar-A2": [3000, 2137.5963718820863], "guitar-A3#": [6000, 2143.8548752834467], "guitar-A3": [9000, 2140.5895691609976] } }

On Sun, Dec 18, 2022 at 10:58 PM rymdmetafor @.***> wrote:

UPDATE:

I found a work around using the exposedData Howl object:

` const [volume, setVolume] = useState(0.75); const [play, exposedData] = useSound([pianoSoundsOgg, pianoSoundsMp3, pianoSoundsM4a], { sprite: pianoSoundData.sprite, volume: volume, });

function handleChangeVolumeOnClick() { if (volume === .75) { setVolume(.25) exposedData.sound.volume(.25) // update howl object volume at the same time as state. } }

} ` what is "pianoSoundData.sprite" in your solution?

— Reply to this email directly, view it on GitHub https://github.com/joshwcomeau/use-sound/issues/43#issuecomment-1357178463, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJVT3RBOC3FV3EPQDEZEDLTWOABRLANCNFSM4SEZAVAA . You are receiving this because you commented.Message ID: @.***>

-- Scott Wolf, DMA Oxnard College - Professor of Music www.scottwolfguitar.com

All Strings Considered http://www.scottwolfguitar.com/podcast.html Follow on Twitter - @allstrings https://twitter.com/allstrings Subscribe free on iTunes https://itunes.apple.com/us/podcast/all-strings-considered/id562425515 - Subscribe - Please Rate!

Clueed commented 5 months ago

Update for 2024:

const [volume, setVolume] = useState(1)

const [play, exposedData] = useSound(...)

useEffect(() => {
    if (exposedData.sound) exposedData.sound._volume = volume
}, [volume])

exposedData.sound._volume = newVolume

How come there are no well-maintained sound libraries?

cjinghong commented 3 months ago

When using sprites, hot reloading does not work anymore. When react calls commitHookEffectListMount after hot reloading, this gets called in use-sound

React__default.useEffect(function () {
    if (sound) {
      sound.volume(volume);
      sound.rate(playbackRate);
    } // A weird bug means that including the `sound` here can trigger an
    // error on unmount, where the state loses track of the sprites??
    // No idea, but anyway I don't need to re-run this if only the `sound`
    // changes.
    // eslint-disable-next-line react-hooks/exhaustive-deps

  }, [volume, playbackRate]);

where sound.rate(playbackRate); fails in howler because self._sprite is undefined TypeError: self._sprite[sound._sprite] is undefined.

Your comment suggest you're already aware of this issue. This is more a inconvinience than anything serious, so i created this issue just to keep track of this bug.

Whats wrong with including sound in the useEffect dependency?