简体   繁体   English

如何使用 componentWillUnmount()?

[英]How to use componentWillUnmount()?

I am new using React-Native and I'm creating a music player for a streaming app and almost everything works fine, it plays in the background but when I want to switch to another album or playlist it does not cut the song that is playing to play the new one, it plays the previous song and the new one at the same time.我是使用 React-Native 的新手,我正在为流媒体应用程序创建音乐播放器,几乎一切正常,它在后台播放,但是当我想切换到另一张专辑或播放列表时,它不会剪切正在播放的歌曲新的,它同时播放上一首歌曲和新一首歌曲。

It shows me this warning:它向我显示了这个警告:

Warning: Can't perform a React state update on an unmounted component.警告:无法对未安装的组件执行 React state 更新。 This is a no-op, but it indicates a memory leak in your application.这是一个无操作,但它表明您的应用程序中存在 memory 泄漏。 To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.要修复,请取消 componentWillUnmount 方法中的所有订阅和异步任务。

But I don't know how to cancel all subscriptions and asynchronous tasks.但是我不知道如何取消所有订阅和异步任务。

Here is my code.这是我的代码。

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,
      interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
      playsInSilentModeIOS: true,
      interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
      shouldDuckAndroid: true,
      staysActiveInBackground: true,
      playThroughEarpieceAndroid: true,
    });
  }

  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,0,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,
    color: "#fff",
  },
  controls: {
    flexDirection: "row",
    color: "#fff",
  },
  durationContainer: {
    flexDirection: "row",
  },
  durationTextLeft: {
    flex: 0.5,
    textAlign: "left",
    fontSize: 16,
    fontWeight: "bold",
    color: "white",
  },
  durationTextRight: {
    flex: 0.5,
    textAlign: "right",
    fontSize: 16,
    fontWeight: "bold",
    color: "white",
  },
});  ```

This seems to be an architectural problem.这似乎是一个架构问题。

If you are in the ReproductorMusica and need to leave that screen to go to the AlbumScreen you're not unloading the last instance (which you've lost, since you only had a reference in the ReproductorMusica).如果您在ReproductorMusica中并且需要将该屏幕留给 go 到AlbumScreen ,那么您不会卸载最后一个实例(您已经丢失了,因为您在 ReproductorMusica 中只有一个参考)。

To solve this problem, your Audio.Sound needs to be "global and unique".要解决这个问题,您的Audio.Sound需要是“全局且唯一的”。 So you can access from any screen, and it's always the same instance.因此,您可以从任何屏幕访问,而且始终是同一个实例。

I really encourage you to change your components to function components.You are using both for no reason, and class components are harder to use state management.我真的鼓励您将您的组件更改为 function 组件。您无缘无故地使用这两个组件,并且 class 组件更难使用 state 管理。 You can change to function components and use just "useEffect" hook to do everything you need.您可以更改为 function 组件并使用“useEffect”挂钩来完成您需要的一切。 Read more about here: https://reactjs.org/docs/hooks-effect.html在此处阅读更多信息: https://reactjs.org/docs/hooks-effect.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 ReactJs 中正确使用 componentWillUnmount() - How to properly use componentWillUnmount() in ReactJs 如何使用componentWillUnmount在React.js中删除setInterval - How to use componentWillUnmount to remove setInterval in React.js 如何删除componentWillUnmount()中的函数调用? - How to remove function call in componentWillUnmount()? 如何取消ComponentWillUnmount中的所有请求? - How to cancel ALL requests in ComponentWillUnmount? 如何在react中正确清除componentWillUnmount()上的Interval? - How to clearInterval on componentWillUnmount() correctly in react? 在 componentWillUnmount 方法中取消所有订阅和异步,如何? - Cancel All Subscriptions and Asyncs in the componentWillUnmount Method, how? 如何将 componentDidMount() 和 componentWillUnmount 转换为 useEffect()? - How do I convert componentDidMount() and componentWillUnmount to the useEffect()? 如何停止对 componentWillUnmount 的 Firestore `get` 查询 - How to stop Firestore `get` query on componentWillUnmount 我应该如何处理React中的componentWillUnmount中的离开动画? - How should I handle a leave animation in componentWillUnmount in React? 我们如何使用 React 钩子实现 componentWillUnmount? - How can we implement componentWillUnmount using react hooks?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM