在屏幕之间切换时,获取“无法在未安装的组件上执行React状态更新”

时间:2019-11-18 08:39:46

标签: reactjs react-native google-cloud-firestore

在Home.js和Chat.js文件之间切换时,出现以下警告:“ 无法对已卸载的组件执行React状态更新。这是空操作,但它指示内存要修复,请在componentWillUnmount方法中取消所有订阅和异步任务”。我删除了Chat.js上的唯一侦听器,并尝试仅在将组件安装到Home.js中时设置状态,并在卸载后将其删除,但仍然收到此警告。

Home.js

import React, { Component } from "react";
import { View, FlatList } from "react-native";
import { ListItem } from "react-native-elements";
import fireStoreDB from "../database/FirestoreDB";

let _isMounted = false;

export default class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      usersInfo: [],
      refreshing: false
    };
  }

  componentDidMount() {
    _isMounted = true;
    this.LoadUsers();
  }

  componentWillUnmount() {
    _isMounted = false;
  }

  LoadUsers = () => {
    fireStoreDB
      .getAllUsersExceptCurrent()
      .then(users =>
        Promise.all(
          users.map(({ id, username, avatar }) =>
            fireStoreDB
              .getUserLastMessage(fireStoreDB.getUID, id)
              .then(message => ({ id, username, avatar, message }))
          )
        )
      )
      .then(users => {
        if (_isMounted) {
          this.setState({
            usersInfo: users.filter(x => typeof x.avatar !== "undefined"),
            refreshing: false
          });
        }
      });
  };

  renderItem = ({ item }) => (
    <ListItem
      onPress={() => {
        this.props.navigation.navigate("Chat", {
          userTo: item.id,
          UserToUsername: item.username,
          LoadUsers: this.LoadUsers
        });
      }}
      title={item.username}
      subtitle={item.message}
      leftAvatar={{ source: { uri: item.avatar } }}
      bottomDivider
      chevron
    />
  );

  render() {
    return (
      <View>
        <FlatList
          data={this.state.usersInfo}
          renderItem={this.renderItem}
          keyExtractor={item => item.id}
          refreshing={this.state.refreshing}
          onRefresh={() => {
            this.setState({ refreshing: true });
            this.LoadUsers();
          }}
        />
      </View>
    );
  }
}

Chat.js

import React, { Component } from "react";
import { View, KeyboardAvoidingView } from "react-native";
import { HeaderBackButton } from "react-navigation-stack";
import { GiftedChat } from "react-native-gifted-chat";
import * as Progress from "react-native-progress";
import fireStoreDB from "../database/FirestoreDB";

const Themes = {
  primaryTheme: "#30D921",
  secondaryTheme: "#B32D83",
  layoutTheme: "#c0c0c0"
};

export default class Chat extends Component {
  static navigationOptions = ({ navigation }) => ({
    title: navigation.getParam("UserToUsername"),
    headerLeft: (
      <HeaderBackButton
        onPress={() => {
          navigation.state.params.LoadUsers();
          navigation.goBack();
        }}
      />
    )
  });

  constructor(props) {
    super(props);
    this.state = {
      messages: [],
      userToId: this.props.navigation.getParam("userTo")
    };
  }

  componentDidMount() {
    fireStoreDB.getMessages(
      message =>
        this.setState(previousState => ({
          messages: GiftedChat.append(previousState.messages, message)
        })),
      this.chatId
    );
  }

  componentWillUnmount() {
    fireStoreDB.removeSnapshotListener(this.chatId);
  }

  // gifted chat user props
  get user() {
    return {
      _id: fireStoreDB.getUID,
      name: fireStoreDB.getName,
      avatar: fireStoreDB.getAvatar
    };
  }

  // merge ids between two parties for one to one chat
  get chatId() {
    const userFromId = fireStoreDB.getUID;
    const chatIdArray = [];
    chatIdArray.push(userFromId);
    chatIdArray.push(this.state.userToId);
    chatIdArray.sort(); // prevents other party from recreating key
    return chatIdArray.join("_");
  }

  render() {
    if (this.state.messages.length === 0) {
      return (
        <View
          style={{
            alignItems: "center",
            marginTop: 260
          }}
        >
          <Progress.Bar indeterminate color={Themes.primaryTheme} />
        </View>
      );
    }
    return (
      <View style={{ flex: 1 }}>
        <GiftedChat
          messages={this.state.messages}
          onSend={messages => fireStoreDB.sendMessages(messages, this.chatId)}
          user={this.user}
        />
        <KeyboardAvoidingView behavior="padding" keyboardVerticalOffset={80} />
      </View>
    );
  }
}

FirestoreDB.js

  removeSnapshotListener = chatId => {
    firebase
      .firestore()
      .collection("messages")
      .doc(chatId)
      .collection("chats")
      .orderBy("createdAt")
      .onSnapshot(() => {});
  };

1 个答案:

答案 0 :(得分:1)

更新:

通过实施,您无法取消订阅messages集合。 您可以尝试从getMessages返回退订函数,然后在componentWillUnmount中使用它

FirestoreDB.js

getMessages = (callback, chatId) => {
  return firebase
      .firestore()
      .collection("messages")
      .doc(chatId)
      .collection("chats")
      .orderBy("createdAt")
      .onSnapshot(callback);
}

Chat.js

  componentDidMount() {
    this.unsubcribe = fireStoreDB.getMessages(
      message =>
        this.setState(previousState => ({
          messages: GiftedChat.append(previousState.messages, message)
        })),
      this.chatId
    );
  }

  componentWillUnmount() {
     this.unsubcribe();
  }