为什么“this.setState()”会对未安装的组件发出警告?

时间:2018-01-30 10:57:35

标签: react-native react-redux react-navigation

我收到警告“只能更新已安装或安装的组件。这通常意味着您在未安装的组件上调用了setState,replaceState或forceUpdate。这是following code的无操作”。在GitHub,您可以找到firebase和Redux的完整工作反应导航示例。如果一个比我更熟练的人看到代码,我认为可以看到问题。

当我从“roles2”跳到“home”导航时,我不知道如何补偿这个警告。你能找到这个bug吗?

import React, { Component } from "react";
import { Text, View, TouchableHighlight, TouchableOpacity, ListView, StatusBar, ScrollView, StyleSheet } from "react-native";
import Styles from "./../../App.scss";
import Firebase from "./../Util/database";
import Item from "./item";
const Uuid = require('uuid/v1');
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import { NavigationActions, SafeAreaView } from "react-navigation";
import { connect } from "react-redux";

var db = Firebase.firestore();

const list = ['Loading...']

export default class Empty extends Component {

constructor(props) {
  super(props);
  this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})

  this.state = {
    dataSource: this.ds.cloneWithRows(list),
  };

  this.roles = db.collection("roles").get();
  this.renderItem = this.renderItem.bind(this)
  this.setItemsFromFirestore = this.setItemsFromFirestore.bind(this);
}

setItemsFromFirestore(roles) {
  roles.then((querySnapshot) => {
  // get children as an array
  var items = [];
  querySnapshot.forEach((child) => {
    items.push({
      label: `${child.data().label}`,
      description: `${child.data().description}`,
      id: `${child.id}`
    });
  });

  this.setState({
    dataSource: this.ds.cloneWithRows(items),
  });
});
}

componentWillUpdate(nextProps, nextState) {
  this.roles = db.collection("roles").get();
  this.setItemsFromFirestore(this.roles);
}

componentDidMount() {
  this.setItemsFromFirestore(this.roles);
}

renderItem(item, navigation) {
  return (
   <Item key={Uuid()} label={item.label} description={item.description} onPress={ () => {
    const param = item.param;
    const route = item.route;
    const navigateAction = NavigationActions.navigate({
      routeName: 'role',
      params: {
        label: `${item.label}`,
        description: `${item.description}`,
        id: `${item.id}`
      }
    });
    navigation.dispatch(navigateAction);
  }} />
 )
}

static navigationOptions = props => {
  const { navigation } = props;
  const { state, setParams } = navigation;
  const { params } = state;
  return {
  title: "Rollen (Cloud)",
  headerTintColor: Styles.ci_Header.color,
  headerStyle: {
    height: Styles.ci_Header.height,
    backgroundColor: Styles.ci_Header.backgroundColor
  },
  headerRight: (
    <FontAwesome
      name= {'plus'}
      size={18}
      style={{ color: Styles.ci_Header.color, paddingHorizontal: 5}}
      onPress={() => {
        const id = `${Uuid()}`;
        var data = {
          id: {id},
          label: `Neue Rolle (${id.substring(0,6)}...)`,
          description: ''
        };
        var setDoc = db.collection('roles').doc(id).set(data);
      }}
    />
  )
 };
};

render() {
 return (
  <View style={{ flex: 1 }}>
    <ListView
        dataSource={this.state.dataSource}
        renderRow={item => this.renderItem(item, this.props.navigation)} />
    <StatusBar barStyle="light-content" />
  </View>
  );
 }
}

我是新手,对导航做出反应,并没有得到我做错的事。

你能找到这个错误吗?

2 个答案:

答案 0 :(得分:2)

此错误表示即使在卸载组件后也调用了setState方法。这通常是由异步API调用引起的。因此,在您移动到其他页面后,您的API调用会返回结果。要避免此警告,可以在 componentDidMount 的组件类中将变量设置为true,并在调用setState方法之前检查该变量是否具有true值。

componentDidMount(){
  this.isMounted = true;
}

fetchData(){
 if(this.isMounted){
  this.setState();
 }
}

答案 1 :(得分:0)

我找到了解决方案,但并不满意。我用

this.mounted = false;
this.state = {
  isMounted: true,
  ... 
};

在卸载时我使用

componentWillUnmount() {
   this.mounted = false;
   this.setState( {isMounted: false} );
   console.log('Will Unmount '+componentName);
}

现在看。在componentWillUpdate i log

 console.log("mounted?: "+this.state.isMounted +" (isMounted-Stat) - "+this.mounted+" (mounted)");

并且控制台抛出

13:28:53: Will Update roles2
13:28:53: Will Unmount roles2
13:28:53: mounted?: true (isMounted-Stat) - false (mounted)

这意味着当我将其定义为组件内的参数时,我可以使用this.mounted,但状态不会使用Unmount进行更新。这在我看来不合逻辑,但我和它一起生活。使用此解决方案(constructorcomponentWillUnmountcomponentWillUpdate),它可以正常运行并且警告已经消失。

我真的很喜欢更好的方法,因为在Unmount之后放置组件时会发出警告。因此,即使组件保持未安装状态,也会调用函数setState。当我在卸载中调用setState时,参数未设置。