diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-07-31 13:12:02 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-07-31 13:12:02 +0200 |
| commit | b2cd730fb78d2dd647bd7bb7ea6691a83d160238 (patch) | |
| tree | baa05b7d44923e72918107d159b6afbd331ca2a4 /apps/web/src/components/editor/audio-waveform.tsx | |
| parent | 5f4f3cc6c420d5fe37bf8f8dffa9368e75b9b60e (diff) | |
| parent | f255ccb818358b90edd0c1bc1f3a690dc1e729ac (diff) | |
| download | opencut-b2cd730fb78d2dd647bd7bb7ea6691a83d160238.tar.gz | |
Merge branch 'staging' of https://github.com/mazeincoding/AppCut into staging
Diffstat (limited to 'apps/web/src/components/editor/audio-waveform.tsx')
| -rw-r--r-- | apps/web/src/components/editor/audio-waveform.tsx | 85 |
1 files changed, 65 insertions, 20 deletions
diff --git a/apps/web/src/components/editor/audio-waveform.tsx b/apps/web/src/components/editor/audio-waveform.tsx index a673f995..372a31c5 100644 --- a/apps/web/src/components/editor/audio-waveform.tsx +++ b/apps/web/src/components/editor/audio-waveform.tsx @@ -19,22 +19,21 @@ const AudioWaveform: React.FC<AudioWaveformProps> = ({ useEffect(() => { let mounted = true; - + let ws = wavesurfer.current; + const initWaveSurfer = async () => { if (!waveformRef.current || !audioUrl) return; try { - // Clean up any existing instance - if (wavesurfer.current) { - try { - wavesurfer.current.destroy(); - } catch (e) { - // Silently ignore destroy errors - } + // Clear any existing instance safely + if (ws) { + // Instead of immediately destroying, just set to null + // We'll destroy it outside this function wavesurfer.current = null; } - wavesurfer.current = WaveSurfer.create({ + // Create a fresh instance + const newWaveSurfer = WaveSurfer.create({ container: waveformRef.current, waveColor: "rgba(255, 255, 255, 0.6)", progressColor: "rgba(255, 255, 255, 0.9)", @@ -46,15 +45,28 @@ const AudioWaveform: React.FC<AudioWaveformProps> = ({ interact: false, }); + // Assign to ref only if component is still mounted + if (mounted) { + wavesurfer.current = newWaveSurfer; + } else { + // Component unmounted during initialization, clean up + try { + newWaveSurfer.destroy(); + } catch (e) { + // Ignore destroy errors + } + return; + } + // Event listeners - wavesurfer.current.on("ready", () => { + newWaveSurfer.on("ready", () => { if (mounted) { setIsLoading(false); setError(false); } }); - wavesurfer.current.on("error", (err) => { + newWaveSurfer.on("error", (err) => { console.error("WaveSurfer error:", err); if (mounted) { setError(true); @@ -62,7 +74,7 @@ const AudioWaveform: React.FC<AudioWaveformProps> = ({ } }); - await wavesurfer.current.load(audioUrl); + await newWaveSurfer.load(audioUrl); } catch (err) { console.error("Failed to initialize WaveSurfer:", err); if (mounted) { @@ -72,17 +84,50 @@ const AudioWaveform: React.FC<AudioWaveformProps> = ({ } }; - initWaveSurfer(); - - return () => { - mounted = false; - if (wavesurfer.current) { + // First safely destroy previous instance if it exists + if (ws) { + // Use this pattern to safely destroy the previous instance + const wsToDestroy = ws; + // Detach from ref immediately + wavesurfer.current = null; + + // Wait a tick to destroy so any pending operations can complete + requestAnimationFrame(() => { try { - wavesurfer.current.destroy(); + wsToDestroy.destroy(); } catch (e) { - // Silently ignore destroy errors + // Ignore errors during destroy + } + // Only initialize new instance after destroying the old one + if (mounted) { + initWaveSurfer(); } - wavesurfer.current = null; + }); + } else { + // No previous instance to clean up, initialize directly + initWaveSurfer(); + } + + return () => { + // Mark component as unmounted + mounted = false; + + // Store reference to current wavesurfer instance + const wsToDestroy = wavesurfer.current; + + // Immediately clear the ref to prevent accessing it after unmount + wavesurfer.current = null; + + // If we have an instance to clean up, do it safely + if (wsToDestroy) { + // Delay destruction to avoid race conditions + requestAnimationFrame(() => { + try { + wsToDestroy.destroy(); + } catch (e) { + // Ignore destroy errors - they're expected + } + }); } }; }, [audioUrl, height]); |
