amplify-js: Signing-out throws 'Warning: Can't call setState(or forceUpdate) on...'

New to aws-amplify-react-native library. When I sign-out I get this warning.

Warning: Can't call setState (or forceUpdate) on an unmounted component. 
This is a no-op, but it indicates a memory leak in your application. 
To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. in Authenticator (created by Wrapper)

android emulator - nexus_5x_api_25_5554

Here is a simple code that I used. Am I doing something wrong?

import React from 'react';
import { Text, View } from 'react-native';
import Amplify from 'aws-amplify';
import awsConfig from './src/aws-exports';
import { withAuthenticator } from 'aws-amplify-react-native';

Amplify.configure(awsConfig);

class App extends React.Component {
  render() {
    return (
      <View><Text>Hello world</Text></View>
    );
  }
}

export default withAuthenticator(App, { includeGreetings: true });

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 6
  • Comments: 18 (1 by maintainers)

Commits related to this issue

Most upvoted comments

I am still getting this warning when signing out after navigating to another page using aws-amplify-react:

Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. in class_1 (at signin.js:5) in div (at signin.js:4) in SignInPage (at _app.js:33)

@powerful23 Is this still a known issue for aws-amplify-react or is my implementation wrong by chance?

This is still an issue in aws-amplify-react … I use a hub listener to detect signIn and signOut to run my signIn and signOut dispatching… from the Authentication Manager with the Hub listener I dispatche all of my login logic to determine usernames, settings, etc… then I change the location from the result of this… to the signed in areas. But still, after all of this, the Authenticators own listener finally decides to trigger signedIn, but the component has well and truly been unmounted by this stage.

This is 100% what is occurring in the react native and react js apps. People leave and navigate away from the login after login has successfully occurred, but the hub is still performing tasks while the Authenticator has been unmounted. Is there some kind of way to sync the ‘signIn, and / or signedIn’ components of the Hub, instead of providing SignedIn for the Authenticator Hub component and the external Hub component. Why are they even a different thing? Can’t they just be the same?

If I listen to signedIn, … it never happens because you can’t listen to signedIn from the Hub.listener… but it somehow does trigger, but it’s way too late.

We need to somehow allow the Hub to listen for the signedIn state… not signIn… we don’t care if we’re about to signIn, because at this stage, anything could be anywhere.

This also related to my issue that <Greetings> doesn’t show anything anymore… if I sign in with my old method which was horrific, where containers were not seperate, and they were all running dependant on each other, it worked fine, but it was horrible code.

I wish this would just plain work.

@amirmishani … you’re right. The latest 2.3.0 @ Stable fixes the unmounted component issue.

@michaelcuneo thanks for your feedback! We have a plan to refactor the Hub module recently and will try the best to solve the issues you mentioned.

@amant finally managed to get rid of this warning! The origin of the problem is here. The Promise gets triggered but is not resolved before the component is unmounted. My solution? I used promise-cancel and a custom Authenticator.

export default class Authenticator extends React.Component {
  // ...
  componentWillMount() {
    this.checkUser(); // <-- problematic line
  }

  componentWillUnmount() {
    this.checkingUser.cancel();
    this.checkingUser.abort();
  }
  
  // ...

  checkUser() {
    const { authState } = this.state;
    const statesJumpToSignIn = ['signedIn', 'signedOut', 'loading'];
   // use promise-cancel
    this.checkingUser = promiseCancel(Auth.currentAuthenticatedUser())
    this.checkingUser.promise.then((user) => {
      if (user) {
        this.handleStateChange('signedIn', null);
      } else if (statesJumpToSignIn.includes(authState)) {
        this.handleStateChange(startScreen, null);
      }
    })
    .catch((err) => {
      if (statesJumpToSignIn.includes(authState)) {
        this.handleStateChange(startScreen, null);
      }
      logger.debug(err);
    });
  }

  // ...
}

I don’t know if this is an acceptable solution, but it worked. Glad to create a PR if appreciated.

Hope this helps