【问题标题】:Can't call setState (or forceUpdate)无法调用 setState(或 forceUpdate)
【发布时间】:2019-03-27 08:49:32
【问题描述】:

我在控制台中看到此错误并尝试了很多解决方案都没有效果

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

【问题讨论】:

  • firebase 连接似乎有问题。
  • @sumitkumarpradhan 不,在 firebase 上一切都很好。

标签: javascript react-native


【解决方案1】:

错误很明显:componentWillUnmount 不应包含 this.setState 或任何修改状态的尝试。在React documentation中提到:

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

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

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

  componentWillUnmount(){
    this.unmounted = true;
  }

【讨论】:

  • 我还从 componentWillUnmount 中删除了所有内容,但仍然出现相同的错误。
  • 还是同样的问题,我一会儿附上视频
  • 我添加了一个视频
  • @YousefAlsbaihi 尝试将上述相同的检查应用于您调用setState 的任何位置。 AppLoading 组件也可能是原因。
【解决方案2】:

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

【讨论】:

  • 您刚刚引用了文档,请阅读我的代码,很明显我在componentWillUnmount()中没有任何内容@
【解决方案3】:
  if(isLogged && isReady) {
            return (
          <GalioProvider theme={materialTheme}>
            <Block flex>
              {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
              <Screens />
            </Block>
          </GalioProvider>
        );

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

尝试使用 if 和 else,

【讨论】:

  • 我试过if(isReady) { if(isLogged){ return ( ....etc ); }else{ return ( ...etc ); } }
猜你喜欢
  • 1970-01-01
  • 2023-04-08
  • 2018-10-28
  • 2018-11-03
  • 1970-01-01
  • 2019-03-10
  • 1970-01-01
  • 2019-01-07
  • 2019-02-11
相关资源
最近更新 更多