Firebase user signOut doesn't work in react native - javascript

I'm building an app and I'm handling the authentication with Firebase. The signIn create user functions work in the intended way, but for some reason, the signOut function doesn't work. When the button for the SignOut is clicked, the user should be signed out, but instead, he stays signed in
const signOutUser = () =>{
console.log(authentication.currentUser.email)//before calling this is test#test.com
signOut(authentication)
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error);
})
console.log("entered sign out functions")
console.log(authentication.currentUser.email)//after above code runs this is till test#test.com
}
Could somebody please advise what I'm doing wrong?

const signOutUser = () => {
console.log(authentication.currentUser.email);
signOut(authentication).then((result) => {
console.log(result);
console.log("entered sign out functions");
console.log(authentication.currentUser.email);
}).catch((e) => { console.log(e) })
}
or
const signOutUser = async() => {
// add try catch if you want
console.log(authentication.currentUser.email);
const result = await signOut(authentication);
console.log("entered sign out functions");
console.log(authentication.currentUser.email);
}
You should await the signOut or write your code in then(). If this is still not working, you probably made a mistake with your signOut(authentication) function.

Related

React-Native onSubmitEditting taking too much time to execute function

I am following a react-native tutorial but am having some trouble with React contexts and ActivityIndicator, I dont know where the problem lies, but I will try to be as descriptive as possible.
The problem:-
The code :
I am using contexts to provide the app with the location that has been searched and then searching for that location within my mock data, later returning the restaurants around that location.
complete source code at https://github.com/diivi/KiloBite/blob/main/src/services/location/location.context.js
Here I am using the onSearch function and passing it as a context prop to my search box to use with onSubmitEditing.
In your code you call onSearch and there you setILoading(true)
and setKeyword(searchKeyword).
Then in the useEffect you use the keyword you set in onSearch. Your useEffect runs only in keyword changes (see dependencies).
Try to add onSearch in your dependencies (look below).
Or maybe even locationRequest, locationTransform.
I would also try setIsLoading and generally try to put as dependencies everything you use in your useEffect.
const onSearch = (searchKeyword) => {
setIsLoading(true);
setKeyword(searchKeyword);
};
useEffect(() => {
if (!keyword.length) {
return;
}
locationRequest(keyword.toLowerCase())
.then(locationTransform)
.then((result) => {
setIsLoading(false);
setLocation(result);
})
.catch((err) => {
setIsLoading(false);
setError(err);
});
}, [keyword, onSearch]);
BUT, at the end I wonder, why you use a useEffect?
Why don't you just move all the code in onSearch:
const onSearch = (searchKeyword) => {
setIsLoading(true);
// setKeyword(searchKeyword); // not needed
if (!searchKeyword.length) {
return;
}
locationRequest(searchKeyword.toLowerCase())
.then(locationTransform)
.then((result) => {
setIsLoading(false);
setLocation(result);
})
.catch((err) => {
setIsLoading(false);
setError(err);
});
};

Getting current user after sign in with Firebase

I want to send a verification email after user sign up. I wrote that code but if i want to get the current user with firebase on react native it always return null. How can i fix it?
Here is the sign up function:
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(navigation.navigate("WaitingRoom"))
.catch((err) => console.log(err));
And also email verification function in WaitingRoom:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
user
.sendEmailVerification()
.then(() => {
console.log(":)");
})
.catch((err) => {
console.log(err);
});
} else {
console.log(":(");
}
});
I also tried firebase.auth().currentUser but it return null too.
From your comment above: "It happens but there is a delay and sometimes i have to reload page. I think i have to wait for response or something like that."
Yes, as explained in the doc, you need to wait that the Auth object has finished initializing.
This is why you should:
Either use the onAuthStateChanged() observer and put the desired code/ business logic in the if (user) {} block, where you are sure user is not null.
OR, manually check that firebase.auth().currentUser is not null before triggering the code/ business logic.
Concretely, based on what I understand from your question, you could/should call navigation.navigate("WaitingRoom") in the onAuthStateChanged() observer, as follows:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
user
.sendEmailVerification()
.then(() => {
navigation.navigate("WaitingRoom");
})
.catch((err) => {
console.log(err);
});
} else {
console.log(":(");
}
});

How to let function continue if a return is empty

I'm working on a chat application and right now i'm working on the ability to create a new chat. To prevent the user to be able to create duplicate chats, i came up with this.
user1 is pre-defined. user2 is defined by entering it into a form. handleSubmit checks if this already exist and if "isChat" returns an id from my database the user gets redirected to the already existing chat.
I have trouble with the other part. If "isChat" is undefined my function wont continue and stops at the first await function.
async function handleSubmit(event) {
event.preventDefault();
const isChat = await getChatId(user1, user2);
if (isChat) {
setChatId(isChat);
setDefinedPartnerName(true);
} else {
await initiateNewChat(user1, user2, messages);
const chatId = await getChatId(user1, user2);
setChatId(chatId);
setDefinedPartnerName(true);
}
}
This is my fetch for this:
//Get chat ID by user1 and user2
export async function getChatId(user1, user2) {
return fetch(`/api/${user1}/${user2}`, {
method: 'GET'
})
.then(response => {
if (response.status !== 200) {
throw new Error(response.statusText);
}
return response;
})
.then(response => response.json());
}
This function cant return anything if there are no records for these two users.
Maybe the error fell through "throw"?
try:
export async function getChatId(user1, user2) {
return fetch(`/api/${user1}/${user2}`, {
method: 'GET'
})
.then(response => {
if (response.status !== 200) {
// throw new Error(response.statusText);
return false;
}else{
return response;
}
})
.then(response => response.json());
}
The syntax for error handling can also be improved:
https://www.tjvantoll.com/2015/09/13/fetch-and-errors/
Solved it on my express route.
My express route has a try...catch function and i gave the catch part of it a response.json(false);
It is a hotfix. But I really don't want to spend a lot of time on backend stuff.
Thanks for your help everyone

Why is my Firestore call not resolving before going further with the next .then()?

I thought I had a simple function:
database change trigger (.onUpdate)
find out which change is possibly important for a notification (prepareNotifications(change))
ask firebase if there are records that want a notification about that change (getDatabaseNotifications(changeWithNotification))
sent notifications (sentNotifications(changeWithNotification))
I'm stuck for a couple off days now on how to resolve the Firebase call before moving on.
tried to Promise.all([getDatabaseNotifications()])
tried to chain this function like this:
changes
then firebase call
then sent notifiactions
What is happening:
I get the changes,
The call to Firebase is done,
But before waiting for the result it moves on to sending notifications.
It finds no notifications in Firebase (but there are notifications!)
It's gathering the notifications (array [])
... here I push a test notification ...
It's sending 1 notification (the test notification)
Then it resolves the Firebase notifications (this should be resolved before).
Then the function stops without doing anything anymore.
This is how my function looks now. Can someone explain how I can wait on Firebase?
exports.showUpdate = functions.firestore
.document('shows/{showId}')
.onUpdate((change, context) => {
return prepareNotifications(change) // check if and which notifications to get out of the firebase database
.then(changes => {
console.log('changes');
console.log(changes);
if(changes) {
const gatherData = [];
changes.forEach(change => {
console.log('change');
console.log(change);
getDatabaseNotifications(change.showId, change.ring, change.ringNumber) // firebase call
.then(data => {
gatherData.push([...gatherData, ...data]);
console.log('gatherData');
console.log(gatherData);
})
.catch(err => {
console.log(err);
})
})
return gatherData;
}
return null;
})
.then(notifications => {
console.log('notifications');
console.log(notifications);
notifications.push(testData); // add some test notifications
if (notifications && notifications.length > 0) {
sentNotifications(notifications); // sent notifications
return 'sending notifications';
}
return 'no notifications to sent';
})
.catch(err => {
Sentry.captureException(new Error(`Showupdate sending notifications not ok. Error message: ${err.message}`));
})
});
Updated code which works! thanks to your examples.
exports.showUpdate = functions.firestore
.document('shows/{showId}')
.onUpdate((change, context) => {
return prepareNotifications(change) // check if and which notifications to get out of the firebase database
.then(changes => {
if(changes) {
return getDbRecords(changes);
}
})
.then(notifications => {
if (notifications && notifications.length > 0) {
sentNotifications(notifications); // sent notifications
return 'sending notifications';
}
return 'no notifications to sent';
})
.catch(err => {
Sentry.captureException(new Error(`Showupdate sending notifications not ok. Error message: ${err.message}`));
})
});
function getDbRecords(changes) {
const gatherData = [];
const gatherDataPromises = [];
changes.forEach(change => {
gatherDataPromises.push(
getDatabaseNotifications(change.showId, change.ring, change.ringNumber) // firebase call
.then(data => {
gatherData.push(...data);
})
);
});
return Promise.all(gatherDataPromises)
.then(() => { return gatherData }
);
}
This section of your code doesn't handle promises properly, it creates a bunch of work but then will return gatherData before any of it has happened, which is why you don't see any notifications:
if(changes) {
const gatherData = [];
changes.forEach(change => {
console.log('change');
console.log(change);
getDatabaseNotifications(change.showId, change.ring, change.ringNumber) // firebase call
.then(data => {
gatherData.push([...gatherData, ...data]);
console.log('gatherData');
console.log(gatherData);
})
.catch(err => {
console.log(err);
})
})
return gatherData;
}
Notably, you probably want that return gatherData to be chained off the set of promises that are generated by the entire set of calls to getDatabaseNotifications.
Something like:
if(changes) {
const gatherData = [];
const gatherDataPromises = [];
changes.forEach(change => {
console.log('change');
console.log(change);
gatherDataPromises.push(
getDatabaseNotifications(change.showId, change.ring, change.ringNumber) // firebase call
.then(data => {
gatherData.push([...gatherData, ...data]);
console.log('gatherData');
console.log(gatherData);
})
);
});
return Promise.all(gatherDataPromises)
.then(() => { return gatherData });
}
I removed the catch statement to allow the error to bubble up to the top level catch.
Caution: I have not tested this, as I don't have sample data or the code for getDatabaseNotifications, but the general approach should solve your current problem. Likewise, it allows all the calls to getDatabaseNotifications to run in parallel, which should be significantly faster than just awaiting on them in sequence.
That said, you do have other problems in this code -- for example, the return null just below the block I am discussing will likely lead you into trouble when you try to use notifications.push() in the following then() (but this also appears to be test code).
I think it's because of the async nature of the methods. So, instead of waiting "getDatabaseNotifications()" to finish it's job, it jumps into ".then(notifications =>{}" and in this case gatherData returns empty.
putting await before calling the method might work.
await getDatabaseNotifications(change.showId, change.ring, change.ringNumber)

Firebase signInWithEmailAndPassword not firing .then() until after UI focus changes

I'm using firebase .signInWithEmailAndPassword(email, password).then() for authentication in a react-native Android project.
I have the function called on an onPress button event. The authentication does take place but for some reason, the .then() does not fire unless I tap somewhere else on the screen. It will happily wait 5 mins until I tap somewhere other than the button to fire.
I can see that the auth is taking place. It's just the .then() promise that hangs until focus is shifted away from the button.
I'm using react-native 0.59.5 and firebase 5.1.0 node libraries. I've tried console.logging each step and it's clear the then() is where it fails. Strangely catch() works immediately.
export const loginUser = ({ email, password }) => {
return dispatch => {
dispatch({ type: LOGIN_USER })
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(() => {
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(user => loginUserSuccess(dispatch, user))
.catch(loginUserFail(dispatch))
})
}
}
const loginUserFail = dispatch => {
dispatch({ type: LOGIN_USER_FAIL })
}
const loginUserSuccess = (dispatch, user) => {
console.log('Firing success')
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user
})
}
In the above example, loginUserFail will run immediately if auth fails but loginUserSuccess will wait indefinitely until I tap somewhere else in the application.
Do you have your remote debugger open in a Chrome browsers?
Close it (debugger), reload app in simulator and it will work as expected.
Just stop the Remote Debugger in your application, hope this will help
try to remove the "then" promisse:
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(error => {
dispatch(loginUserFail(error));
});
After that try to create an action with this comand:
firebase.auth().onAuthStateChanged(user => {
if (user) {
console.log('success sign in');
dispatch(loginUserSuccess(user));
} else {
// No user is signed in.
}
});

Categories