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

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.
}
});

Related

Firebase user signOut doesn't work in react native

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.

Chaining an action behind an asynchronous function

I'm currently trying to create a chain of actions that only happen sequentially, and not asynchronously.
It's a sign-in function, where I want the following actions to happen in this order:
User clicks on sign in
Sign in request sent
If successful, data fetch is executed
Console log that it's successful
Then push to dashboard with fetched data
However what's actually happening is the following:
User clicks on sign in
Sign in request sent
If successful, data fetch is started
User pushed to dashboard
Data fetch continues, and then re-renders with the data
I tried integrating async / await, but weirdly it's not doing it as I expected. I think it's me misunderstanding what I need to do more than anything.
Here's the function I want all of this to happen through:
const handleSignInSubmit = async (e) => {
e.preventDefault()
await signIn(email, password)
console.log("Trying to push")
history.push("/dashboard")
}
And here is my sign-in function:
const signIn = (email, password) => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => {
var user = userCredential.user;
setCurrentUser(user)
})
.then(async () => {
console.log("Fetching data...")
await fetchData()
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode)
console.log(errorMessage)
});
}
Can anyone tell me what I'm doing wrong here?
You are awaiting the return value of signIn.
signIn doesn't have a return statement so it returns undefined.
You can only usefully await a promise.
return the return value of firebase.auth.etc.etc.catch() which is the promise you have been working with.

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(":(");
}
});

Button only works on double tapping while on remote debugging in react native

The problem is when ever, i use remote debugging i needs to double tap a button in order to execute an redux action. I dont know why its happening, am using firebase inorder to signin with email and password.
My Redux Action:
export const loginRequest = (email, password) => {
return (dispatch) => {
dispatch({ type: LOGIN_SPINNER, payload: true })
firebase.auth().signInWithEmailAndPassword(email, password)
.then((data) => {
dispatch({ type: LOGIN_SUCCESS, payload: data })
NavigationService.navigate('Drawer')
dispatch({ type: LOGIN_SPINNER, payload: false })
})
.catch((error) => {
dispatch({ type: LOGIN_UNSUCCESS, payload: error.message })
dispatch({ type: LOGIN_SPINNER, payload: false })
console.log(error)
})
}
}
So from above, one my first tap dispatch({ type: LOGIN_SPINNER, payload: true }) it works ( as i can see actions in remote debugging ) and it stops there itself, and again on second tap the firebase function gets executed and its works.
Where is the problem ? In redux or firebase ? Please guide me through to figure this out !
I also have this problem when developing with React Native.
This is not a problem of redux or firebase, but a minor bug of the react-native debugger. It only happens if you make an api call in debug mode, the result will not be updated unless you tab anywhere on the screen once more after the api call is done.
I don't have a solution to 'fix' that but the delay will not be existed anymore in the released version (or if you disable debug mode) so I think you may just ignore it.

Handle async requests in react native / redux

I'm using firebase to build an app with react native. I'm struggling with how I should structure my redux actions within my app.
As is stands I have a function that will fetch a users profile. I make a reference to the firebase firestore and then use then and catch statements to resolve the promise returned. Here is where my problem comes into it.
return(dispatch){
dispatch({type: GET_PROFILE})
var docRef = firebase.firestore().doc('users/' + userUid);
docRef.get()
.then(() => {
dispatch({type: GET_PROFILE_SUCCESS})
})
.catch(() => {
dispatch({type: GET_PROFILE_FAIL})
})
}
I am dispatching the action GET_PROFILE so that when my render function is called in my profile screen, it will load a spinner while the user waits.
The problem I've got is that if the user isn't connected to the internet. When they make the request, the action is sent to redux but GET PROFILE SUCCESS / FAIL is never dispatched, as having no internet connection isn't an error
As a result all the user sees is a spinner until they restart the app. I basically want to alert the user that they need a connection to the internet.
I'm new to react native, Could someone advise me what's the best way to do this in react native?
Thanks
You can get network informations with NetInfo and store it in redux :
In your main component :
componentDidMount() {
NetInfo.isConnected.fetch().then((isConnected) => {
store.dispatch({ type: 'CHANGE_CONNECTION_STATUS', isConnected });
});
NetInfo.isConnected.addEventListener('connectionChange', this.handleConnectionChange);
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectionChange);
handleConnectionChange = (isConnected: boolean) => {
store.dispatch({ type: 'CHANGE_CONNECTION_STATUS', isConnected }));
}
Then you can wrap your request with an if statement to handle offline use cases :
return(dispatch){
if(store.getState().isConnected) {
dispatch({type: GET_PROFILE})
var docRef = firebase.firestore().doc('users/' + userUid);
docRef.get()
.then(() => {
dispatch({type: GET_PROFILE_SUCCESS})
})
.catch(() => {
dispatch({type: GET_PROFILE_FAIL})
})
} else {
Alert.alert('You are offline');
}
}
You can use this piece of code for network fail condition
return(dispatch){
dispatch({type: GET_PROFILE})
var docRef = firebase.firestore().doc('users/' + userUid);
docRef.get()
.then(() => {
dispatch({type: GET_PROFILE_SUCCESS})
},
// ADD THESE LINES
(error) => {
dispatch({type: GET_PROFILE_FAIL})
})
.catch(() => {
dispatch({type: GET_PROFILE_FAIL})
})
}

Categories