Calling a function inside .then() is throwing an error - firebase

I'm trying to perform some task with firebase and calling some functions inside promise without any callback function and this is giving me an error.
Here is my code
onButtonPress = () => {
const {email, password} = this.state
this.setState({error: '', loading: true});
firebase.auth().signInWithEmailAndPassword(email, password)
.then(this.onAuthSuccess().bind(this))
.catch(()=>{
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(this.onAuthSuccess().bind(this))
.catch(this.onAuthFailed().bind(this))
})
}
onAuthSuccess() {
this.setState({
email: '',
password: '',
error: '',
loading: false
})
}
onAuthFailed() {
this.setState({
error: "Authentication Failed",
loading: false
})
}
Here is the error message that I'm getting
undefined is not an object (evaluating '_this.onAuthSuccess().bind()')

3 ways of dealing with this context in ES6.
Use the bind keyword
onAuthSuccess() {
...
}
firebase.auth()
.then(this.onAuthSuccess.bind(this));
.catch(this.onAuthFailed.bind(this));
}
Use arrow function to avoid prebinding
onAuthSuccess = () => {
...
}
firebase.auth()
.then(this.onAuthSuccess);
.catch(this.onAuthFailed);
}
Bind your methods in the constructor
constructor(props) {
super(props);
this.onAuthSuccess = this.onAuthSuccess.bind(this);
}

Not 100% as the good ol this context is confusing!
so I think you want to get rid of the bind() and instead use => on your functions. Using the fat arrows will reset the context of this so this.setState should be right in the context of your class based component.
Here is an example of what I mean
onAuthSuccess = () => {
this.setState({
email: "",
password: "",
error: "",
loading: false
});
};
onAuthFailed = () => {
this.setState({
error: "Authentication Failed",
loading: false
});
};
onButtonPress = () => {
const { email, password } = this.state;
this.setState({ error: "", loading: true });
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => this.onAuthSuccess())
.catch(() => {
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(() => this.onAuthSuccess())
.catch(() => this.onAuthFailed());
});
};

Related

Firebase Dispatch Error Object { "error": "Invalid claim 'kid' in auth header: 'tB0M2A' with iat: '1659290899'", }

I am trying to develop a react-native-app but everything was good. Once I have changed the authentication rules in firebase real time database. From that time, I am not able to POST/GET any request from firebase. I am storing the idToken which is returned after a user sign in the application in redux store.
case actionTypes.AUTHENTICATE_USER:
return {
...state,
isAuth: true,
token: action.payload
}
export const authUser = token => {
return {
type: actionTypes.AUTHENTICATE_USER,
payload: token
}}
The Login action code is as follows:
export const tryLogin = (email, password, navigate) => dispatch => {
fetch("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY, {
method: "POST",
body: JSON.stringify({
email: email, password: password, returnSecuretoken: true
}),
headers: {
"Content-Type": "application/json"
}
})
.catch(err => {
console.log(err);
alert("Authentication Failed");
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert(data.error.message);
}
else {
dispatch(authUser(data.idToken));
navigate("Home");
}
console.log(data);
})}
And I get the error while running the following code:
export const addPlace = place => (dispatch, getState) => {
let token = getState().token;
console.log("Add place Token:", token);
fetch(`https://first-react-native-proje-7df03-default-rtdb.asia-southeast1.firebasedatabase.app/places.json?auth=${token}`, {
method: "POST", body: JSON.stringify(place)
})
.catch(error => console.log(error))
.then(response => response.json())
.then(data => console.log("Dispatch Error", data))}
export const loadPlaces = () => (dispatch, getState) => {
let token = getState().token;
fetch(`https://first-react-native-proje-7df03-default-rtdb.asia-southeast1.firebasedatabase.app/places.json?auth=${token}`)
.catch(err => {
alert("Something Went Wrong, Sorry!");
console.log(err);
})
.then(res => res.json())
.then(data => {
const places = [];
for (let key in data) {
places.push({
...data[key],
key: key
})
}
dispatch(setPlaces(places));
})}
My firebase rule is as follows as I am still in initial phase:
{"rules": {
".read": "auth!=null" , // 2022-8-4
".write": "auth!=null", // 2022-8-4
}}
I am not getting any way to solve this. Please help.
Solved. The problem was with the returnSecureToken:true. I wrote returnSecuretoken which was creating the error. It will be:
export const tryLogin = (email, password, navigate) => dispatch => {
fetch("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY, {
method: "POST",
body: JSON.stringify({
email: email, password: password, ***returnSecureToken: true***
}),
headers: {
"Content-Type": "application/json"
}
})
.catch(err => {
console.log(err);
alert("Authentication Failed");
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert(data.error.message);
}
else {
dispatch(authUser(data.idToken));
navigate("Home");
}
console.log(data);
})
}

Accessing vuex actions inside a promise

I'm struggling to understand this conceptually.
So I'm trying to use a Vuex store action from within a second .then() function of a promise ( this.$store.dispatch('setAdditionalUserInfo', doc.data())) , and I'm getting the error of TypeError: Cannot read property '$store' of undefined.
Why can't I access this in the .then() function?
socialLogin () {
const provider = new firebase.auth.GoogleAuthProvider()
firebase.auth().signInWithPopup(provider)
.then(cred => {
const protoslug = cred.user.displayName + ' ' + cred.user.uid
this.slug = slugify(protoslug, {
replacement: '-',
remove: /[$*_+~.()'"!\-:#']/g,
lower: true
})
db.collection('users').doc(this.slug).set({
alias: this.slug,
role: 'customer',
// eslint-disable-next-line #typescript-eslint/camelcase
user_id: cred.user.uid
})
// set the user in the vuex store
this.$store.dispatch('setUser', cred.user)
return cred.user
})
.then((cred) => {
db.collection('users').where('user_id', '==', cred.uid)
.get()
.then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
console.log(doc.data())
this.$store.dispatch('setAdditionalUserInfo', doc.data())
})
})
.catch(function (error) {
console.log('Error getting documents: ', error)
})
})
}
I can see that the data is returned as it is logged out in the console. The project is in typescript, so its preventing me from trying self = this.
To propagate the value of this all the way down, you need to always use arrow functions. Change these lines:
.then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
console.log(doc.data())
this.$store.dispatch('setAdditionalUserInfo', doc.data())
})
})
.catch(function (error) {
console.log('Error getting documents: ', error)
})
to use arrow functions:
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.data())
this.$store.dispatch('setAdditionalUserInfo', doc.data())
})
})
.catch((error) => {
console.log('Error getting documents: ', error)
})

Why is firebase throwing a permission error after sign-out?

In a react-native application, dispatching an action that invokes firebase-auth to sign-out ends in a firebase permission error:
Here's the method inside the drawer component that dispatches the action:
logout = () => {
this.props
.logoutUser()
.then(() => {
this.props.navigation.navigate('Login');
})
.catch((err) => alert(err));
};
and here's the logout action:
export const logoutUser = () => {
return (dispatch) => {
return new Promise((resolve, reject) => {
firebase
.auth()
.signOut()
.then(() => {
dispatch({ type: types.RESET_APP });
console.log('Dispatching types.RESET_APP');
resolve();
})
.catch((error) => reject(error.message));
});
};
};
When executed, the screen reverts back to the login screen as desired. Console logs Dispatching types.RESET_APP, and THEN the error above displays.
authStateChanged Listener in my login:
export const loginUser = (email, password) => {
return (dispatch) => {
dispatch({ type: types.LOGIN_USER });
// listen for change in auth state before signing in
return new Promise((resolve, reject) => {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((userCredential) => {
console.log('User Credential: ' + JSON.stringify(userCredential));
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('Logged in: ' + user.email);
loginUserSuccess(dispatch, user);
resolve(user);
} else {
console.log('Authentication state changed, user object is null...');
//resetAuth();
}
});
// No longer need to listen to auth state
unsubscribe();
})
.catch((error) => {
console.log('Error during Email sign-in: ' + error);
loginUserFail(dispatch, error.message);
});
});
};
};
auth state observer is unsubscribed in the login function, so whats causing this?

Why are my redux actions not firing correctly?

I am trying to implement a check for authentication and to login/logout users using redux and firebase. I have the following code:
Action Types:
export const LOGIN_REQ = 'AUTH_REQ';
export const LOGOUT_REQ = 'LOGOUT_REQ';
export const AUTH_SUCCESS = 'AUTH_SUCCESS';
export const AUTH_FAILED = 'AUTH_FAILED';
export const GET_AUTH = 'GET_AUTH';
Reducers:
import * as ActionTypes from './ActionTypes';
export const auth = (state = {
isAuth: false,
user: null
}, action) => {
switch (action.type) {
case ActionTypes.LOGIN_REQ:
return { ...state, isAuth: false, user: null };
case ActionTypes.LOGOUT_REQ:
return { ...state, isAuth: false, user: null };
case ActionTypes.AUTH_FAILED:
return { ...state, isAuth: false, user: null };
case ActionTypes.AUTH_SUCCESS:
return { ...state, isAuth: true, user: action.payload };
case ActionTypes.GET_AUTH:
return state;
default:
return state;
}
}
Thunks:
export const getAuth = () => (dispatch) => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('Get AUTH called');
dispatch(authSuccess());
}
else {
console.log('Get AUTH called');
dispatch(authFailed());
}
});
}
export const loginReq = (email, password, remember) => (dispatch) => {
firebase.auth().signInWithEmailAndPassword(email, password)
.then((cred) => {
if (remember === false) {
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);
console.log('Logged In with Redux without persist');
}
else {
console.log('Logging in with Persist');
}
console.log('Dispatching Success !');
dispatch(authSuccess(cred.user.uid));
})
.catch((err) => {
console.log(err);
dispatch(authFailed(err));
});
}
export const logoutReq = () => (dispatch) => {
firebase.auth().signOut()
.then(() => dispatch(getAuth()))
.catch((err) => console.log(err));
}
export const authSuccess = (uid = null) => ({
type: ActionTypes.AUTH_SUCCESS,
payload: uid
});
export const authFailed = (resp) => ({
type: ActionTypes.AUTH_FAILED,
payload: resp
});
And I am calling it from a component as shown below:
const mapStateToProps = state => {
return {
isAuth: state.isAuth,
user: state.user
}
}
const mapDispatchToProps = dispatch => ({
getAuth: () => { dispatch(getAuth()) },
loginReq: (email, password, remember) => { dispatch(loginReq(email, password, remember)) },
logoutReq: () => { dispatch(logoutReq()) }
})
handleLogin() {
this.props.loginReq(this.state.email, this.state.password, this.state.remember);
}
handleLogOut() {
this.props.logoutReq();
}
<BUTTON onClick=()=>this.handleLogOut()/handleLogin()>
I am close to tears because I cannot figure out why my loginReq fires one or many gitAuth() methods even when i click on the button once. This happens only for the loginReq() action. I have not specified anywhere that loginReq() should fire it.
Also i have called the getAuth() method in the component did mount method of my main screen which checks authentication status once at the start of the app.
EDIT: I have console logged in the component did mount method in the main component so I know that this getAuth() call is not coming from there.
Imo the answer is badly done, try to reestructure it better, what you call "Thunks" are actually "Actions". But if I were to tell you something that could help is that maybe the problem lies in the thunk middleware config or with the way firebase is beign treated by the dispatcher, so I would say that you better try coding an apporach with the react-redux-firebase library (this one: http://react-redux-firebase.com/docs/getting_started ) it makes easier to connect redux with a firebase back end. Other great reference, the one that I learned with, is The Net Ninja's tutorial playlist about react, redux and firebase.
A friend of mine told me this has to do with something known as an 'Observer' which is in the onAuthStateChange() provided by firebase. Basically there is a conflict between me manually considering the user as authenticated and the observer doing so.

react native with firebase validation input field

I want to validate my login form in react native. but i used another Firebase logging function in onChangetext in react native.
This is my onPress function in the login button press.
async onLoginPress() {
this.setState({ errorMessage: null, loading: true });
const { email, password } = this.state;
console.log(email);
console.log(password);
firebase
.auth()
.signInWithEmailAndPassword(this.state.email, this.state.password)
.then(() => {
this.setState({ loading: false });
// this.props.navigation.navigate("Friendlist");
})
.catch(() => {
//var errorCode = error.code;
//var errorMessage = error.message;
this.setState({
error: 'AUTHENTICATION FAILED',
loading: false
});
});
await AsyncStorage.setItem("email", email);
await AsyncStorage.setItem("password", password);
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({
loading: false
});
}
});
}
and this is my onChangetext define in TextInput
onChangeText={email => this.setState({ email })}
I want to add validate functions with these functions. how caI i do that?
You can add multiple functions in the onChangeText callback as
onChangeText={async email => {
await method1()
await method2()
...
}}
but I would recommend you to use callback since you're using setState. This ensures the setState is updated before the callback in it is called
onChangeText={email => this.setState({ email }, () => this.validate(email))}

Resources