组件关闭后 Expo 停止播放音频
Expo stop audio playing after component closed
我正在使用 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;
};
}, []);
您可以做的是在 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
组件
// All Imports etc
function Audio({ playing }) {
//Rest of your code
const [soundStatus, setSoundStatus] = useState({ status: null, icon: play });
const [audioStatus, setAudioStatus] = useState(0);
useEffect(() => {
// This useEffect runs whenever there is a change in playing Prop
if (soundStatus.status) {
if (soundStatus.status.isLoaded) {
sound.stopAsync().then(() => {
if (playing === true) {
setSoundStatus({ status: st, icon: play });
setAudioFinished(false);
} else {
// Pause your Audio here
}
});
}
}
}, [playing]);
//Rest of your code
}
export default Audio;
我解决了这个问题。我有两个问题。第一个是在 onPlaybackStatusUpdate
函数中,当组件已经卸载时,我试图用剩余的音频状态更新 <Text>
,所以它给出了一个错误。我通过在 onPlaybackStatusUpdate
函数中添加 if(mountedRef.current)
来修复此问题。
我遇到的第二个问题是我尝试 运行 空 useEffect dependency array
( useEffect(() => {},[])
) 中的清理函数。清理函数运行,但是声音为null,所以无法停止声音。我通过在 useEffect
依赖项数组中添加 sound
状态并检查 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);
}
}
};
来自'expo-av'官方文档
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { Audio } from 'expo-av';
export default function App() {
const [sound, setSound] = React.useState();
async function playSound() {
console.log('Loading Sound');
const { sound } = await Audio.Sound.createAsync(
require('./assets/Hello.mp3')
);
setSound(sound);
console.log('Playing Sound');
await sound.playAsync(); }
// This part is what you are looking for
React.useEffect(() => {
return sound
? () => {
console.log('Unloading Sound');
sound.unloadAsync(); }
: undefined;
}, [sound]);
我正在使用 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;
};
}, []);
您可以做的是在 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
组件
// All Imports etc
function Audio({ playing }) {
//Rest of your code
const [soundStatus, setSoundStatus] = useState({ status: null, icon: play });
const [audioStatus, setAudioStatus] = useState(0);
useEffect(() => {
// This useEffect runs whenever there is a change in playing Prop
if (soundStatus.status) {
if (soundStatus.status.isLoaded) {
sound.stopAsync().then(() => {
if (playing === true) {
setSoundStatus({ status: st, icon: play });
setAudioFinished(false);
} else {
// Pause your Audio here
}
});
}
}
}, [playing]);
//Rest of your code
}
export default Audio;
我解决了这个问题。我有两个问题。第一个是在 onPlaybackStatusUpdate
函数中,当组件已经卸载时,我试图用剩余的音频状态更新 <Text>
,所以它给出了一个错误。我通过在 onPlaybackStatusUpdate
函数中添加 if(mountedRef.current)
来修复此问题。
我遇到的第二个问题是我尝试 运行 空 useEffect dependency array
( useEffect(() => {},[])
) 中的清理函数。清理函数运行,但是声音为null,所以无法停止声音。我通过在 useEffect
依赖项数组中添加 sound
状态并检查 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);
}
}
};
来自'expo-av'官方文档
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { Audio } from 'expo-av';
export default function App() {
const [sound, setSound] = React.useState();
async function playSound() {
console.log('Loading Sound');
const { sound } = await Audio.Sound.createAsync(
require('./assets/Hello.mp3')
);
setSound(sound);
console.log('Playing Sound');
await sound.playAsync(); }
// This part is what you are looking for
React.useEffect(() => {
return sound
? () => {
console.log('Unloading Sound');
sound.unloadAsync(); }
: undefined;
}, [sound]);