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)
})
Related
For some reason this code fail to sign up on firebase,
app.post('/signup', (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle
}
let token, userId;
db.doc(`/users/${newUser.handle}`).get().then(doc => {
if (doc.exists) {
return res.status(400).json({ handle: 'this handle already exists' })
} else {
return firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
}
})
.then(data => {
userId = data.user.uid;
return data.user.getIdToken();
})
.then(idToken => {
token = idToken;
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
createdAt: new date().toISOString(),
userId
}
return db.doc(`/users/${newUser.handle}`).set(userCredentials)
})
.then(() => {
return res.status(201).json({ token });
})
.catch(err => {
if (err.code === "auth/email-already-in-use") {
return res.status(400).json({ email: 'Email is alrready in use' })
} else {
return res.status(500).json({ general: 'something went wrong, please try again' })
}
})
});
I always get { general: 'something went wrong, please try again' } , i am using postman to mimic the request to firebase,
This code works perfectly:
firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
.then(data => {
return data.user.getIdToken();
})
.then(token => {
return res.status(201).json({token})
})
.catch(err => {
console.error(err);
return res.status(500).json({error: 'something went wrongly'})
})
The first trial is from a tutorial i am following in Youtube and sadly it doesn't work
On the backend, you can use Firebase Admin SDK to get details about any user but it does not have any ability to login on behalf of user.
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?
I have a simple pub sub cloud function
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
exports.updateNews = functions.pubsub
.topic("firebase-schedule-cronForNews-us-central1")
.onPublish(message => {
axios
.get(
"https://newsapi.org/v2/top-headlines?apiKey=241414&sources=espn-cric-info"
)
.then(result => {
return result.data.articles.forEach(article => {
db.collection("news").add(article);
});
})
.then(result => {
console.log(result);
return result;
})
.catch(error => {
console.log(error);
return error;
});
return null;
});
The function is being invoked but it is not writing to firestore the same code works when I convert this to http function.
You may try returning the promises chain and using a batched write, as follows:
exports.updateNews = functions.pubsub
.topic("firebase-schedule-cronForNews-us-central1")
.onPublish(message => {
return axios // Note the return here
.get(
"https://newsapi.org/v2/top-headlines?apiKey=241414&sources=espn-cric-info"
)
.then(result => {
const batch = admin.firestore().batch();
result.data.articles.forEach(article => {
const docRef = admin.firestore().collection("news").doc();
batch.set(docRef, article);
});
return batch.commit();
})
.then(result => { // You don't need this then if you don't need the console.log
console.log(result);
return null;
});
});
I am trying to return a promise from dispatch so that I can do something like this in my react component
this.props.dispatch(requestLogin(data))
.then((res) => {
Navigate.toHome()
}).catch((err) => {
this.showErrorMessage()
})
currently I wrapped my fetch to reuse the common things i pass on the server API and to put some logs for debugging. I did it like this:
export const query = (path, opts) => {
// common config and boilerplates here
// e.g add device id to every api request
return fetch(opts.url, reqOpts)
.then((response) => {
console.log('response received')
if (response.ok) {
return response.json()
} else
console.log('response not ok')})
.then((respData) => {
if (respData.status === true) {
console.log('response success')
return respData
} else {
const errObj = respData
errObj.server = true
throw errObj
}
}).catch((err) => {
console.log('error catched')
if (err.server) {
throw err
}
throw { status: false, errors: { error_code: 'ERR_FATAL', error_msg: 'Something went wrong.' }, err }
})
then my action creator is like this:
export function requestLogin (data) {
return function (dispatch) {
const opts = {
method: 'POST',
body: data,
}
return query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
},
(data2) => {
// the thrown error actually returns here
// this returned value goes to the .then of the dispatch
return data2
},
).catch((err) => {
// this is not executed
return err
})
}
}
whats happening is
this.props.dispatch(requestLogin(data))
.then((res) => {
// the error actually goes here
Navigate.toHome()
}
(err) => {
// not here
}).catch((err) => {
// or here
this.showErrorMessage()
})
First, it's important to understand that the second argument you give then(onFulfilled, onRejected), which is onRejected, is another syntax to catch, so because it's written before your catch in the action creator, you get to there when the query function throws an error. that is why the catch block isn't executed. (read about promise's then).
after you catch your error in onRejected, it returns a promise, which is not an error anymore(the promise's state is fulfilled and not rejected).
if you want the promise to get to the catch block, you should change your action creator:
return query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
},
(data2) => {
// the thrown error actually returns here
// this returned value goes to the .then of the dispatch
return new Promise((resolve,reject) => {
reject(data2)
}
})
that will return a promise, which is rejected, so it will be caught by the catch block.
also, you can change the
return new Promise((resolve,reject) => {
reject(data2)
}
with
throw 'error'
or
Promise.reject(data2)
let me know if you need any further explanation.
When you doing:
query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
},
(data2) => {
// the thrown error actually returns here
// this returned value goes to the .then of the dispatch
return data2
})
.catch((err) => {
// this is not executed
return err
})
It's actually, you do catch the error of query function already, then you return data2. It means you want to return a Promise success (resolve) with data2. The same thing happen with catch.
To fix it, you just need to remove the (data2) => {} and the catch block.
query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
})
The second way, in case you still want to do something with the error before, you need to return Promise.reject:
query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
})
.catch((err) => {
// you can do something with error, and still return a promise.reject here
console.log('I found an error here', err)
return Promise.reject(err)
})
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());
});
};