Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rerender for each instance of use-sound #42

Closed
martinjuhasz opened this issue Sep 29, 2020 · 10 comments
Closed

rerender for each instance of use-sound #42

martinjuhasz opened this issue Sep 29, 2020 · 10 comments

Comments

@martinjuhasz
Copy link

When using multiple use-sound instances, the page re-renders its content depending on how many hooks are used.

F.e.:

const Page = () => {
  const sound1 = useSound(sample1)
  const sound2 = useSound(sample2)
  const sound3 = useSound(sample3)

  console.log('render')
  return (<>hello</>)
}

will log render like 14 times. See this codesandbox.

Is this the expected behaviour?

@andrewmclagan
Copy link

Also seeing this

@yomed
Copy link

yomed commented Nov 30, 2020

I dug into this a little bit and found that additional rerenders upon calling play() are caused by this internal use of state:

use-sound/src/index.ts

Lines 116 to 127 in d920ebb

if (isMounted.current) {
sound.once('end', () => {
// If sound is not looping
if (!sound.playing()) {
setIsPlaying(false);
}
});
}
if (isMounted.current) {
setIsPlaying(true);
}

@ghost
Copy link

ghost commented Dec 4, 2020

I also recognized this and I have additionally a known react issue but I don't know how to fix it in this case.

This is my code:


import useSound from 'use-sound';
import Sounds from '../../sounds';
[...]

const BoopButton = () => {
  let filename = Sounds[_AnotherStateVariable_].path; //the state of this parameter changes on user input and it is also a state variable
  const [play] = useSound(filename);

  return <button onClick={() => { play(); doSomethingElse(); }}>Boop</button>;
};
const doSomethingElse = () => {
  [...];
  setAnotherStateVariable('default');
}

The Warning:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in BoopButton

@aelainelong
Copy link

Any updates on this?

@RealKai42
Copy link

I have same Warning, even after I update use-sound to 2.0.1

@mihir0x69
Copy link

Any update on this? The hook is causing seemingly unnecessary rerenders :(

@joshwcomeau
Copy link
Owner

I don't have the bandwidth to look into this right now, but you can avoid having multiple useSound calls by using a sprite. See this example: https://github.com/joshwcomeau/use-sound/blob/master/stories/demos/DrumMachine.js#L28

@binajmen
Copy link

Any update on this? The hook is causing seemingly unnecessary rerenders :(

Same here, a lot of unnecessary rerenders while handling a large amount of items. Did you find a fix?

@yomed
Copy link

yomed commented May 16, 2021

Not a fix, but a workaround would be to use https://github.com/ds300/patch-package and comment out the lines I mentioned above: #42 (comment) (only if you aren't using that functionality).

@joshwcomeau
Copy link
Owner

joshwcomeau commented Jun 4, 2021

Ok, so I just published 4.0.0. The number of renders should be quite a bit lower now. In addition to removing the lines that @yomed found, I've made a few other tweaks that should help.

In order to lower the render count, I had to ditch the isPlaying boolean. This is easy enough to implement on your own, if you need it. A new Storybook story, ShowWhilePlaying, shows an example.

When loading a component with multiple hooks, it will still re-render multiple times per hook. This is because sounds load at different times, and once the sound is loaded, we need to set it into state so that it can be interacted with. I don't expect this to be a problem in most cases, though. And if it is, you can solve it by memoizing the component down-tree (re-renders are super quick in general, they only become slow when you're rendering a lot of stuff. And we can reduce the amount of stuff we're rendering with memoization)

If you have multiple hooks per component, the recommendation is still to use a sprite, as I mentioned above. This is a good idea even without considering the render count.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants