I have a react native app where I use firebase/auth
.
This is what I have in my package.json
file:
"dependencies": {
....
"@react-native-firebase/analytics": "^21.7.1",
"@react-native-firebase/app": "^21.7.1",
"firebase": "10.13",
....
}
Please let me know if I need to have something else in my dependencies.
This is my App.js
file:
import { getAuth, signInWithEmailAndPassword, onAuthStateChanged } from "firebase/auth";
const App = () => {
const [verified, setVerified] = useState(false);
const [currentUser, setCurrentUser] = useState(null);
...
...
...
useEffect(() => {
const auth = getAuth();
const unsubscribe = onAuthStateChanged(auth, (user) => {
if(user){
setCurrentUser(user);
setVerified(user.emailVerified);
}else{
setCurrentUser(null);
}
});
return () => unsubscribe();
}, []);
...
...
...
if(!currentUser){
return (
<NavigationContainer>
<AuthNavigator />
</NavigationContainer>
);
}
else if (currentUser && !verified){
return (
<NavigationContainer>
<VerifyEmail setVerified={setVerified}/>
</NavigationContainer>
);
}
else{
return (
<Provider store={store}>
<NavigationContainer>
<MainNavigator />
</NavigationContainer>
</Provider>
);
}
};
export default App;
Users can log in, they can log out, and for some STRANGE reason, which I can not figure out, after I leave my phone untouched for 20 minutes, they are once again logged out, without even touching the app.
What am I doing wrong?
What you're describing is the expected behavior for the code you have, but it doesn't mean that the user is logged out. Your code is just not waiting long enough for Firebase to validate that they're logged in.
When you restart the app, Firebase automatically restores the user credentials from local storage. To ensure that the credentials are still valid, and that the user hasn't been suspended, it needs to make a call to the server, which happens asynchronously as it takes time (typically 1 to 2 seconds). While this call it ongoing, the login state of the user is unknown and your code fails to handle that.
Specifically, in your code the order in which things happen is:
const [verified, setVerified] = useState(false);
const [currentUser, setCurrentUser] = useState(null); // Step 1
...
...
...
useEffect(() => {
const auth = getAuth();
const unsubscribe = onAuthStateChanged(auth, (user) => { // Step 2
if(user){ // Step 4
setCurrentUser(user);
setVerified(user.emailVerified);
}else{
setCurrentUser(null);
}
});
return () => unsubscribe();
}, []);
...
...
...
if(!currentUser){ // Step 3
return (
<NavigationContainer>
<AuthNavigator />
</NavigationContainer>
);
}
The steps from here:
currentUser
to null
.currentUser
and navigate to the auth screenSo your navigating away (step 3) before you ever hear the initial login state from Firebase (step 4).
The fix is to track whether you are still loading the user's initial auth state, and only navigate once the auth state listener has been called at least once.
In code:
const [verified, setVerified] = useState(false);
const [isLoading, setLoading] = useState(false); // 👈
const [currentUser, setCurrentUser] = useState(null);
...
...
...
useEffect(() => {
const auth = getAuth();
const unsubscribe = onAuthStateChanged(auth, (user) => {
if(user){
setCurrentUser(user);
setVerified(user.emailVerified);
setLoading(false); // 👈
}else{
setCurrentUser(null);
setLoading(false); // 👈
}
});
return () => unsubscribe();
}, []);
...
...
...
if(!isLoading !currentUser){ // 👈
return (
<NavigationContainer>
<AuthNavigator />
</NavigationContainer>
);
You'll typically want to show some loading indicator while isLoading
is true.