如何解决如何使用 componentWillUnmount()?
我是使用 React-Native 的新手,我正在为流媒体应用程序创建音乐播放器,几乎一切正常,它在后台播放,但是当我想切换到另一个专辑或播放列表时,它不会剪切歌曲即播放新曲,同时播放上一曲和新曲。
它向我显示了这个警告:
警告:无法对卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请取消 componentwillUnmount 方法中的所有订阅和异步任务。
但是我不知道如何取消所有订阅和异步任务。
这是我的代码。
import {
StyleSheet,TouchableOpacity,View,Image,imagebackground,Slider,} from "react-native";
import { Title,Text } from "react-native-paper";
import { LinearGradient } from "expo-linear-gradient";
import { Button } from "../components/Button";
import { Audio,Video } from "expo-av";
import firebase from "../utils/firebase";
import "firebase/firestore";
import { Ionicons } from "@expo/vector-icons";
export default function ReproductorAudio(props) {
const { route } = props;
const { canciones } = route.params;
const [duration,setDuration] = useState(0);
const [totalDuration,setTotalDuration] = useState(0);
const cancionesPlaylist = canciones;
console.log(cancionesPlaylist);
return (
<ReproductorMusica
duration={duration}
cancionesPlaylist={cancionesPlaylist}
totalDuration={totalDuration}
/>
);
}
class ReproductorMusica extends React.Component {
state = {
isPlaying: false,playbackInstance: null,currentIndex: 0,duration: 0,volume: 1.0,isBuffering: false,isMounted: false,totalDuration: 0,};
async componentDidMount() {
this.isMounted = true;
try {
await Audio.setAudioModeAsync({
allowsRecordingIOS: false,interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,playsInSilentModeIOS: true,interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,shouldDuckAndroid: true,staysActiveInBackground: true,playThroughEarpieceAndroid: true,});
this.loadAudio();
} catch (e) {
console.log(e);
}
}
async componentwillUnmount() {
Audio.setAudioModeAsync({
allowsRecordingIOS: false,});
}
async loadAudio() {
const { currentIndex,isPlaying,volume } = this.state;
try {
const playbackInstance = new Audio.sound();
const source = {
uri: this.props.cancionesPlaylist[currentIndex].song,};
const status = {
shouldplay: isPlaying,volume,};
playbackInstance.setonPlaybackStatusUpdate(this.onPlaybackStatusUpdate);
await playbackInstance.loadAsync(source,status,false);
this.setState({ playbackInstance });
} catch (e) {
console.log(e);
}
}
onPlaybackStatusUpdate = (status) => {
this.setState({
isBuffering: status.isBuffering,});
};
handlePlayPause = async () => {
const { isPlaying,playbackInstance } = this.state;
isPlaying
? await playbackInstance.pauseAsync()
: await playbackInstance.playAsync();
this.setState({
isPlaying: !isPlaying,});
};
handlePrevIoUsTrack = async () => {
let { playbackInstance,currentIndex } = this.state;
if (playbackInstance) {
await playbackInstance.unloadAsync();
currentIndex < this.props.cancionesPlaylist.length - 1
? (currentIndex -= 1)
: (currentIndex = 0);
this.setState({
currentIndex,});
this.loadAudio();
}
};
handleNextTrack = async () => {
let { playbackInstance,currentIndex } = this.state;
if (playbackInstance) {
await playbackInstance.unloadAsync();
currentIndex < this.props.cancionesPlaylist.length - 1
? (currentIndex += 1)
: (currentIndex = 0);
this.setState({
currentIndex,});
this.loadAudio();
}
};
renderFileInfo() {
const {
playbackInstance,currentIndex,duration,totalDuration,} = this.state;
return playbackInstance ? (
<View style={styles.trackInfo}>
<Image
style={styles.albumCover}
source={{
uri: this.props.cancionesPlaylist[currentIndex].image,}}
/>
<Title style={[styles.trackInfoText,styles.largeText]}>
{this.props.cancionesPlaylist[currentIndex].name}
</Title>
<Title style={[styles.trackInfoText,styles.smallText]}></Title>
<View style={styles.progressContainer}>
<Slider
totalDuration={this.props.cancionesPlaylist[currentIndex].duracion}
onValueChange={(value) =>
this.props.cancionesPlaylist[duration](value)
}
/>
<View style={styles.durationContainer}>
<Text style={styles.durationTextLeft}>{duration}</Text>
<Text style={styles.durationTextRight}>
-{(totalDuration - duration).toFixed(2)}
</Text>
</View>
</View>
{/*<Title style={[styles.trackInfoText,styles.smallText]}>
{this.props.cancionesPlaylist[currentIndex].pista}
</Title>*/}
</View>
) : null;
}
render() {
const { playbackInstance,currentIndex } = this.state;
return (
<imagebackground
style={styles.backgroundImage}
source={{
uri: this.props.cancionesPlaylist[currentIndex].image,}}
blurRadius={25}
>
<View style={styles.container}>
{this.renderFileInfo()}
<View style={styles.controls}>
<TouchableOpacity
style={styles.control}
onPress={this.handlePrevIoUsTrack}
>
<Ionicons
name="arrow-back-circle-outline"
size={48}
color="#fff"
/>
</TouchableOpacity>
<TouchableOpacity
style={styles.control}
onPress={this.handlePlayPause}
>
{this.state.isPlaying ? (
<Ionicons name="ios-pause" size={48} color="#fff" />
) : (
<Ionicons name="ios-play-circle" size={48} color="#fff" />
)}
</TouchableOpacity>
<TouchableOpacity
style={styles.control}
onPress={this.handleNextTrack}
>
<Ionicons
name="arrow-forward-circle-outline"
size={48}
color="#fff"
/>
</TouchableOpacity>
</View>
</View>
</imagebackground>
);
}
}
const styles = StyleSheet.create({
backgroundImage: {
position: "absolute",top: 0,left: 0,bottom: 0,right: 0,},container: {
flex: 1,backgroundColor: "rgba(189,0.3)",alignItems: "center",justifyContent: "center",albumCover: {
width: 250,height: 250,borderRadius: 10,borderWidth: 5,borderColor: "#fff",trackInfo: {
padding: 40,paddingBottom: 0,//backgroundColor: "#000",trackInfoText: {
textAlign: "center",flexWrap: "wrap",color: "#fff",largeText: {
fontSize: 22,smallText: {
fontSize: 16,control: {
margin: 20,controls: {
flexDirection: "row",durationContainer: {
flexDirection: "row",durationTextLeft: {
flex: 0.5,textAlign: "left",fontSize: 16,fontWeight: "bold",color: "white",durationTextRight: {
flex: 0.5,textAlign: "right",}); ```
解决方法
这似乎是一个架构问题。
如果您在 ReproductorMusica
中并且需要离开该屏幕转到 AlbumScreen
,则您不会卸载最后一个实例(您已经丢失了,因为您在ReproductorMusica)。
要解决此问题,您的 Audio.Sound
需要“全局且唯一”。因此,您可以从任何屏幕访问,而且始终是同一个实例。
我真的鼓励您将组件更改为功能组件。您无缘无故地同时使用这两种组件,并且类组件更难使用状态管理。您可以更改为功能组件并仅使用“useEffect”钩子来完成您需要的一切。在此处阅读更多信息:https://reactjs.org/docs/hooks-effect.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。