组件关闭后,Expo 停止播放音频

时间:2021-04-13 20:37:28

标签: reactjs react-native audio expo

我正在使用 expo 的音频 API 来播放声音。 我在 react-native-raw-bottom-sheet 中有一个组件(它是从屏幕底部弹出的),其中包含音频逻辑。

当我关闭弹出窗口时,我希望音频停止播放。我尝试在音频组件中使用清理功能,但出现错误: 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.

主要组件:

<RBSheet
  //props
  onClose({() =>{
  //maybe do something here
 }}
 >
  <Audio /> //this is the adudio component
<RBSheet>

音频组件:

 const [soundStatus, setSoundStatus] = useState({ status: null, icon: play });
 const [audioStatus, setAudioStatus] = useState(0);

 useEffect(() => {
    let mounted = true;

    if (soundStatus.status) {
      if (soundStatus.status.isLoaded) {
        sound.stopAsync().then(() => {
          if (mounted) {
            setSoundStatus({ status: st, icon: play });
            setAudioFinished(false);
          }
        });
      }
    }
    return () => {
      mounted = false;
    };
  }, []);

2 个答案:

答案 0 :(得分:0)

您可以在 @field:DataField(pos = 1, required = true) 中创建一个名为 MainComponent 的状态变量并管理来自该变量的音频。给你看看

将这些行添加到 AudioPlaying

Main Component

然后在 ... const [AudioPlaying, SetAudioPlaying] = useState(false) <RBSheet //props onOpen={() => SetAudioPlaying(true)} // Setting Playing to true when Sheet opens onClose={() => SetAudioPlaying(false)} // Setting Playing to false when Sheet closes > <Audio playing={AudioPlaying} /> // Pass the variable as a Prop here <RBSheet> ... 组件中

Audio

答案 1 :(得分:0)

我解决了这个问题。我有两个problems。第一个是在 onPlaybackStatusUpdate 函数中,当组件已经卸载时,我尝试用剩余的音频状态更新 <Text>,所以它给出了错误。我通过在 if(mountedRef.current) 函数中添加 onPlaybackStatusUpdate 解决了这个问题。

我遇到的第二个问题是我试图在空的 useEffect dependency array (useEffect(() => {},[])) 中运行清理函数。清理功能运行了,但是声音是空的,所以它无法停止声音。我通过在 sound 依赖项数组中添加 useEffect 状态并检查 mountedRef 是否为真(如下所述)来修复它。

 const mountedRef = useRef(null)
 
 //Tracking audio status changes

 //Fix of problem 1
  const onPlaybackStatusUpdate = async (st) => {
    //This is the fucntion which updates the elapsed audio status ( shows remaining seconds like this 0:10/0:53)
    if(mountedRef.current) 
      //set some state here for updating the audio status
  };

  //Loading the file for the first time
  useEffect(() => {
    (async () => {
      if (sound === null) {
      if(audioUrl) {
        try {
            const { sound, status } = await Audio.Sound.createAsync(
              {
                uri: `audioUrl`,
              },
              { shouldPlay: false },
              onPlaybackStatusUpdate //Problem was here
            );

            setSound(sound);
            setSoundStatus({ icon: play, status: status });

            console.log("setting sound");
          } catch (err) {
            console.log(err);
            setSoundStatus({ icon: play, status: null });
          }
      }    
      }
    })();
  }, [audioUrl]);

  //Fix of problem 2
  useEffect(() => {
    mountedRef.current = true;

    return () => {
      stopMusic();
      mountedRef.current = false;
    };
  }, [sound]);

  const stopMusic = async () => {
    if (sound) {
      let st = await sound.stopAsync();
      if (mountedRef.current) {
        setSoundStatus({ status: st, icon: play });
        setAudioFinished(true);
      }
    }
  };