0

Expo documentation states that the Audio.Sound component should be unmounted by an useEffect-hook returning the cleanup function.

const [sound] = useState(new Audio.Sound());
React.useEffect(() => {
return sound
  ? () => {
      console.log('Unloading Sound');
      sound.unloadAsync(); }
  : undefined;
}, [sound]);

I do that but nevertheless getting the warning

Warning: Can't perform a React state update on an unmounted component.

everytime the component dismounts.

Niklas Dada
  • 311
  • 4
  • 17

1 Answers1

1

The Problem was that the Audio.Sound component sent playbackStatus updates to the callback registered with sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate) in the time BETWEEN the cleanup function was called and unloadAsync() returned unsynchronously. And that callback updated other state components which where already unmounted.

Solution

Add a boolean variable to the component (not a useState variable because that will not update immediately) which is set in the cleanup function and acts as a guard for the playbackStatus callback.

const [audio] = useState(new Audio.Sound());
let isUnmounting = false;

useEffect(() => {
    loadAudio(url).then(() => consoloe.log("loaded audio"));
    return () => {
        isUnmounting = true;
        audio.unloadAsync().then(() => console.log("unloaded audio"));
    };
}, [audio]);


async function loadAudio(url) {
    // ...
    audio.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
    try {
        await audio.loadAsync(url);
        // ...
    } catch {
        console.log("Error loading audio");
    }
}


const onPlaybackStatusUpdate = (status) => {
    // this protects against updates on unmounted components 
    // when callback is fired while component is dismounting
    if (isUnmounting) return;
    // ... set the state components you need, like durationInMillis,..
}
Niklas Dada
  • 311
  • 4
  • 17