0
votes

I am using Firebase Auth to handle user registration, login, and logout in a react native app. I am using the following registerUser function:

export const registerUser = async ({ name, email, password }) => {
  try {
    await firebase.auth().createUserWithEmailAndPassword(email, password);
    firebase.auth().currentUser.updateProfile({
      displayName: name
    });

    return {};
  } catch (error) {
    switch (error.code) {
      case "auth/email-already-in-use":
        return {
          error: "E-mail address is already in use."
        };
      case "auth/weak-password":
        return {
          error: "Password is too weak."
        };
      case "auth/too-many-requests":
        return {
          error: "Too many requests. Try again in a minute."
        };
      default:
        return {
          error: "Check your internet connection."
        };
    }
  }
};

which I call in my RegisterScreen with the help of a handleRegister function that is called when the user submits the form:

const handleRegister = async (values) => {
        if (loading) return;
        setLoading(true);
        const response = await registerUser({
            name: values.name,
            email: values.email,
            password: values.password
        });
        if (response.error) {
            Alert.alert('Error', response.error);
        }
        setLoading(false);
    };

Registration works, but I get the following warning:

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

Can someone tell me how to use useEffect to remove this warning?

Update 8/11/2020

I am initializing firebase in a loading screen and am trying to listen to the authentication state as described here. But now I am getting a different warning: "Warning: Cannot update during an existing state transition (such as within 'render'). Render methods should be a pure function of props and state."

const LoadingScreen = props => {
    const [initializing, setInitializing] = useState(true);
    const [user, setUser] = useState();

    if (!firebase.apps.length) {
        firebase.initializeApp(firebaseConfig);
    }

    const onAuthStateChanged = (user) => {
        setUser(user);
        if (initializing) setInitializing(false);
    }

    useEffect(() => {
        const subscriber = firebase.auth().onAuthStateChanged(onAuthStateChanged);
        return subscriber;
    }, []);

    if (initializing) return null;

    if (!user) {
        props.navigation.navigate('Auth');
    } else {
        props.navigation.navigate('App');
    }

    return (
        <View style={styles.screen}>
            <ActivityIndicator size='large' color={Colors.primaryColor} />
        </View>
    );
}
1
By any chance, are you listening to login status changes using onAuthStateChanged inside useEffect as written in the docs? Do you have an empty dependencies array [] as they do in the docs? Not sure if it's relevant, but I had the same issue in my app and I think the missing dependency array was the issue for me.reesaspieces
I suspect that this is the source of the issue, and I have added an update above to reflect how I have changed my loading screen. However, now I have a different error. Do you know how to fix this?blakebullwinkel
Since I wanted to include a code block, I've written an answer below.reesaspieces

1 Answers

0
votes

My Firebase setup was different from yours, but judging by your LoadingScreen code, it looks like you should call your function for initializing Firebase and for navigating inside a useEffect hook. Maybe try something like this?

const LoadingScreen = props => {
    const [initializing, setInitializing] = useState(true);
    const [user, setUser] = useState();

    useEffect(() => {
      if (!user) {
        props.navigation.navigate('Auth');
      } else {
        props.navigation.navigate('App');
      }
      }, [user])

    const onAuthStateChanged = (user) => {
        setUser(user);
        if (initializing) setInitializing(false);
    }

    useEffect(() => {
        // Run once, on mount
        if (!firebase.apps.length) {
          firebase.initializeApp(firebaseConfig);
        }

        const subscriber = firebase.auth().onAuthStateChanged(onAuthStateChanged);
        return subscriber;
    }, []);

    if (initializing) return null;

    return (
        <View style={styles.screen}>
            <ActivityIndicator size='large' color={Colors.primaryColor} />
        </View>
    );
}