【问题标题】:Why "this.setState()" thows a warning for unmounted component?为什么“this.setState()”会对未安装的组件发出警告?
【发布时间】:2018-07-09 05:45:02
【问题描述】:

我在following code 收到警告“只能更新已安装或正在安装的组件。这通常意味着您在未安装的组件上调用了 setState、replaceState 或 forceUpdate。这是一个无操作”。在GitHub,你可以找到完整的带有 firebase 和 Redux 的 react-navigation 示例。我认为如果比我更熟练的人查看代码,就会发现问题。

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

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>
  );
 }
}

我是新手,不知道我做错了什么。

你能找到错误吗?

【问题讨论】:

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


【解决方案1】:

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

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

卸载时我使用

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

现在看。在componentWillUpdate我登录

 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 定义为组件内的参数时,我可以使用它,但状态不会通过卸载更新。在我看来,这不合逻辑,但我接受了。使用此解决方案(constructorcomponentWillUnmountcomponentWillUpdate)它可以工作并且警告消失了。

我真的很喜欢更好的方法,因为在卸载后离开组件时会引发警告。因此,即使组件未挂载,也会在某处调用函数setState。当我在卸载时调用setState 时,未设置参数。

【讨论】:

    【解决方案2】:

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

    componentDidMount(){
      this.isMounted = true;
    }
    
    fetchData(){
     if(this.isMounted){
      this.setState();
     }
    }
    

    【讨论】:

    • 谢谢,这对我有帮助。
    • 这是反应中的反模式。
    猜你喜欢
    • 1970-01-01
    • 2018-10-06
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2018-08-08
    • 2018-09-13
    相关资源
    最近更新 更多