3

I am trying to use React-Navigation Version 5 (not Ver 4) to switch from the authentication screens/stack to the non-authentication screens/stack when the user logs in. A simple example is well demonstrated in the documentation.

However, the documentation does not provide details for using Redux and Google Firebase authentication. After a successful login, I am getting the following warning message.

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 a useEffect cleanup function.

I think that the cause of this warning message is that the call to Redux action (action creator) causes re-rendering of the authentication screen, while the navigation code has already unmounted this screen! How can I update the Redux's store after the authentication screen has been unmounted?

Navigation Code:

...
// If user is logged in -> display the app/main stack
if (props.loggedIn) 
{
    const MyTabs = createBottomTabNavigator();
    return (
        <NavigationContainer>
            <MyTabs.Navigator initialRouteName="UserTypeScreen">
                <MyTabs.Screen name="UserTypeScreen" component={UserTypeScreen}  />
                <MyTabs.Screen name="PermissionsScreen" component={PermissionsScreen} />
            </MyTabs.Navigator>
        </NavigationContainer>
    ); 
}
// If user is NOT logged in -> display the auth stack
else {
    const AuthStack = createStackNavigator();
    return (
        <NavigationContainer>
            <AuthStack.Navigator>
                <AuthStack.Screen name="AuthScreen" component={AuthScreen} />
                <AuthStack.Screen name="AuthLinkScreen" component={AuthLinkScreen} />
            </AuthStack.Navigator>
        </NavigationContainer>
    ); 
}
...

Authentication screen:

...
useEffect( () => {
    const unSubscribe = firebase.auth().onAuthStateChanged( (user) => {
        if (user) {
            const idToken = firebase.auth().currentUser.getIdToken(); 
            const credential = firebase.auth.PhoneAuthProvider.credential(idToken); 

            // The following statement causes a warning message, because it causes re-rendering of an unmounted screen
            props.acLoginUserSuccess(user, credential); 
        } 
    }); 

    return () => {
        unSubscribe();
    };
}, []); 
...

Redux Action Creator:

...
export const acLoginUserSuccess = (user, credential) => {
    return {
        type: LOGIN_USER_SUCCESS,
        payload: { user: user, credential: credential }
  };
};
...
Bilal Abdeen
  • 1,627
  • 1
  • 19
  • 41

2 Answers2

0

I have quickly gone through you code, but here's what I think (could be wrong).

The docs recommend fetching the token on a screen which is mounted (App.js in the example).

This will not be an issue if your firebase.auth() listener in useEffect hook is in App.js .

I think the warning message is shown because when you are in MyTabs route, the AuthScreen is not mounted.

Moving the listener to App.js or on a screen which is in the same stack as BOTH the auth and MyTabs screen will solve the problem I think.

  • Thanks. Actually, I tried that. However, I could not find a way to update Redux's state from within App.js. I don't think it is possible to define a provider (Redux) and use it to update the status within the same component. In other words, it doesn't seem possible to define Redux as a provider in a component and use the "connect" component to access the state within that component, at which Redux is defined as a provider! Sorry, it is difficult to explain without a code example. If I failed to communicate the idea, please let me know. I would update my question with information about this. – Bilal Abdeen Apr 27 '20 at 10:17
  • you can import store and do store.dispatch(action) – clever_username Apr 27 '20 at 11:42
0

I believe that below code is written with idea to get token and store in Redux store.

Is it possible to move this logic after validation of credentials is successful instead of unmount?

please provide valid reason of having this logic in unmount to assess the problem better

firebase.auth().onAuthStateChanged( (user) => {
    if (user) {
        const idToken = firebase.auth().currentUser.getIdToken(); 
        const credential = firebase.auth.PhoneAuthProvider.credential(idToken); 

        // The following statement causes a warning message, because it causes re-rendering of an unmounted screen
        props.acLoginUserSuccess(user, credential); 
    } 
});
Yuvaraj
  • 511
  • 6
  • 9