From 9694c80b041861018c90a2bc395be7d48ce3ce64 Mon Sep 17 00:00:00 2001 From: Daniel at CosmicDNA Date: Fri, 5 Apr 2024 16:46:50 +0100 Subject: [PATCH] :heavy_plus_sign: Add skip feature to workaround https://github.com/joshwcomeau/use-sound/issues/92 --- src/index.d.ts | 1 + src/index.ts | 45 ++++++++++++++++++------------------------- src/types.d.ts | 1 + src/types.ts | 1 + src/use-mount.d.ts | 8 ++++++++ src/use-mount.ts | 24 +++++++++++++++++++++++ src/use-on-mount.d.ts | 8 ++++++-- src/use-on-mount.ts | 10 ++++++---- 8 files changed, 66 insertions(+), 32 deletions(-) create mode 100644 src/use-mount.d.ts create mode 100644 src/use-mount.ts diff --git a/src/index.d.ts b/src/index.d.ts index f430cd8..2b6525b 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -7,6 +7,7 @@ export default function useSound( soundEnabled, interrupt, onload, + skip, ...delegated }?: HookOptions ): ReturnedValue; diff --git a/src/index.ts b/src/index.ts index 6dbad8b..8ebbc41 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import React from 'react'; -import useOnMount from './use-on-mount'; +import useMount from 'use-mount'; import { HookOptions, PlayOptions, PlayFunction, ReturnedValue } from './types'; @@ -13,11 +13,11 @@ export default function useSound( soundEnabled = true, interrupt = false, onload, + skip = false, ...delegated }: HookOptions = {} as HookOptions ) { const HowlConstructor = React.useRef(null); - const isMounted = React.useRef(false); const [duration, setDuration] = React.useState(null); @@ -29,7 +29,7 @@ export default function useSound( onload.call(this); } - if (isMounted.current) { + if (isMounted) { // @ts-ignore setDuration(this.duration() * 1000); } @@ -39,29 +39,22 @@ export default function useSound( }; // We want to lazy-load Howler, since sounds can't play on load anyway. - useOnMount(() => { - import('howler').then(mod => { - if (!isMounted.current) { - // Depending on the module system used, `mod` might hold - // the export directly, or it might be under `default`. - HowlConstructor.current = mod.Howl ?? mod.default.Howl; - - isMounted.current = true; - - new HowlConstructor.current({ - src: Array.isArray(src) ? src : [src], - volume, - rate: playbackRate, - onload: handleLoad, - ...delegated, - }); - } - }); - - return () => { - isMounted.current = false; - }; - }); + const { isMounted } = useMount(async () => { + if (!skip) { + const mod = await import('howler'); + // Depending on the module system used, `mod` might hold + // the export directly, or it might be under `default`. + HowlConstructor.current = mod.Howl ?? mod.default.Howl; + + new HowlConstructor.current({ + src: Array.isArray(src) ? src : [src], + volume, + rate: playbackRate, + onload: handleLoad, + ...delegated, + }); + } + }, [skip]); // When the `src` changes, we have to do a whole thing where we recreate // the Howl instance. This is because Howler doesn't expose a way to diff --git a/src/types.d.ts b/src/types.d.ts index 3383a7c..8807d65 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -8,6 +8,7 @@ export interface HookOptions { interrupt?: boolean; soundEnabled?: boolean; sprite?: SpriteMap; + skip?: boolean; onload?: () => void; } export interface PlayOptions { diff --git a/src/types.ts b/src/types.ts index 89656b2..bc97b42 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,7 @@ export type HookOptions = T & { interrupt?: boolean; soundEnabled?: boolean; sprite?: SpriteMap; + skip?: boolean; onload?: () => void; }; diff --git a/src/use-mount.d.ts b/src/use-mount.d.ts new file mode 100644 index 0000000..2241859 --- /dev/null +++ b/src/use-mount.d.ts @@ -0,0 +1,8 @@ +import { DependencyList } from 'react'; +declare const useMount: ( + callback?: Function, + deps?: DependencyList +) => { + isMounted: boolean; +}; +export default useMount; diff --git a/src/use-mount.ts b/src/use-mount.ts new file mode 100644 index 0000000..db58d18 --- /dev/null +++ b/src/use-mount.ts @@ -0,0 +1,24 @@ +import { DependencyList, useRef } from 'react'; +import useOnMount from './use-on-mount'; + +const useMount = (callback: Function = () => {}, deps: DependencyList = []) => { + // Ref to track component mount state + const isMounted = useRef(false); + + useOnMount(() => { + // Component has mounted, set the flag + if (!isMounted.current) { + isMounted.current = true; + callback(); + } + + // Cleanup function to reset the flag when component unmounts + return () => { + isMounted.current = false; + }; + }, deps); + + return { isMounted: isMounted.current }; +}; + +export default useMount; diff --git a/src/use-on-mount.d.ts b/src/use-on-mount.d.ts index a882399..c7387c7 100644 --- a/src/use-on-mount.d.ts +++ b/src/use-on-mount.d.ts @@ -1,2 +1,6 @@ -import * as React from 'react'; -export default function useOnMount(callback: React.EffectCallback): void; +import { EffectCallback, DependencyList } from 'react'; +declare const useOnMount: ( + callback: EffectCallback, + deps?: DependencyList +) => void; +export default useOnMount; diff --git a/src/use-on-mount.ts b/src/use-on-mount.ts index bb38c7d..5916a0e 100644 --- a/src/use-on-mount.ts +++ b/src/use-on-mount.ts @@ -1,5 +1,7 @@ -import * as React from 'react'; +import { useEffect, EffectCallback, DependencyList } from 'react'; -export default function useOnMount(callback: React.EffectCallback) { - React.useEffect(callback, []); -} +const useOnMount = (callback: EffectCallback, deps: DependencyList = []) => { + useEffect(callback, deps); +}; + +export default useOnMount;