无法调用setState(或forceUpdate)

时间:2019-03-27 08:49:32

标签: javascript react-native

我在控制台中看到此错误,并尝试了许多解决方案,但无济于事

  

ExceptionsManager.js:84警告:无法调用setState(或forceUpdate)   在未安装的组件上。这是空操作,但表示有内存   应用程序泄漏。要解决此问题,请取消所有订阅并   componentWillUnmount方法中的异步任务。       在开始中(在SceneView.js:9)       在SceneView中(位于SwitchView.js:12)       在SwitchView中(位于createNavigator.js:57处)       在导航器中(位于createNavigationContainer.js:376)       在NavigationContainer中(位于App.js:95)

我尝试了这些解决方案以及许多其他解决方案 Link Link Link Link

App.js

import React from 'react';
import { Platform, StatusBar, Image } from 'react-native';
import { AppLoading, Asset } from 'expo';
import AppPreLoader from './components/AppPreLoader'
import { Block, GalioProvider } from 'galio-framework';
import Screens from './navigation/Screens';
import { Images, materialTheme } from './constants/';
import firebaseConfig from './constants/Firebase';
import * as firebase from 'firebase';
import Notlogged from './navigation/Notlogged';
firebase.initializeApp(firebaseConfig);

// cache app images
const assetImages = [
  Images.Onboarding,
];

function cacheImages(images) {
  return images.map(image => {
    if (typeof image === 'string') {
      return Image.prefetch(image);
    } else {
      return Asset.fromModule(image).downloadAsync();
    }
  });
}


export default class App extends React.Component {
  constructor () {
        super();
        this.state = {
            isLogged: false,
            loaded: false,
            isReady: false,
        }
  }

  async componentDidMount () {
    await firebase.auth().onAuthStateChanged((user) => {
      if(user !== null) {
        this.setState({
          isLogged: true,
                    loaded: true
        });
      } else {
        this.setState({
          isLogged: false,
                    loaded: true
        });
      }
    })
  }

  componentWillUnmount(){
  }

  render() {

    if (!this.state.isReady) {
      return (
        <AppLoading
          startAsync={this._loadResourcesAsync}
          onFinish={() => this.setState({ isReady: true })}
          onError={console.warn}
        />
      );
    }

    const {isLogged, loaded, isReady} = this.state;
    if ( ! loaded) {
            return (
        <AppPreLoader/>
        );
        }

    if(isLogged && isReady) {
            return (
          <GalioProvider theme={materialTheme}>
            <Block flex>
              {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
              <Screens />
            </Block>
          </GalioProvider>
        );
    }else{
      return (
        <GalioProvider theme={materialTheme}>
          <Block flex>
            {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
            <Notlogged />
          </Block>
        </GalioProvider>
        );
    }

  }

  _loadResourcesAsync = async () => {
    return Promise.all([
      ...cacheImages(assetImages),
    ]);
  };

  _handleLoadingError = error => {
    console.warn(error);
  };

  _handleFinishLoading = () => {
    this.setState({ isLoadingComplete: true });
  };
}

当我签名并且应用程序进入主屏幕时会出现警告,但是如果我只是在登录后打开应用程序,那也没警告,只有在我登录后才发出警告。

视频显示,如果我没有登录,但如果我尝试登录,则会发生警告

https://streamable.com/s/yjt8x/nvgtbh

3 个答案:

答案 0 :(得分:3)

错误非常明显:{ "sourceName": "Watch", "distance": 0.001970404953280968, "startDate": "2019-03-25T07:29:57Z", "quantity": 1155, "endDate": "2019-03-25T07:39:56Z" } 不应包含componentWillUnmount或任何试图修改状态的尝试。 React documentation中提到了它:

  

您不应在componentWillUnmount()中调用setState(),因为   组件将永远不会被重新渲染。一旦组件实例是   卸载后,将不再安装。

编辑:好的,您的组件还有1个问题:this.setState的处理程序可能在组件卸载期间或之后运行,React将其检测为尝试更新已卸载组件的状态。为了解决这个问题,您可以为组件设置一个布尔值,以检查它是否仍然需要执行firebase.auth().onAuthStateChanged()

setState

答案 1 :(得分:0)

componentWillUnmount()在卸载和销毁组件之前立即被调用。使用此方法执行任何必要的清除,例如使计时器无效,取消网络请求或清除在componentDidMount()中创建的所有订阅。 您不应该在componentWillUnmount()中调用setState(),因为永远不会重新渲染该组件。卸载组件实例后,将永远不会再次安装它。

答案 2 :(得分:0)

  if(isLogged && isReady) {
            return (
          <GalioProvider theme={materialTheme}>
            <Block flex>
              {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
              <Screens />
            </Block>
          </GalioProvider>
        );

在这里,您正在等待isLogged和isReady,而不取决于是否已加载异步数据。 因此,在装入资产之前,要卸载组件,并且在解决对资产加载的承诺时,它试图在不再安装的组件上设置状态。

尝试将if与else一起使用