Firebase authentication in ReactJS - reactjs

I'm trying to authenticate the user using the google. Everything is going fine. But when I try to console.log(this) inside of the onAuthStateChanged() is printing something like
Object { next: componentDidMount(user), error: noop(), complete: noop()
}
​
complete: function noop()​
error: function noop()​
next: function componentDidMount(user)​
<prototype>: Object { … }
But if I console.log(this) outside of the onAuthStateChanged() its working fine with the information of the current class.
What I want is, I want to update the state information with the user details by using this this.setState() method. But this.setState() method is not working inside of the onAuthStateChanged().
How can I do it?
Here is my code
componentDidMount = ()=>{
console.log(this)
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log(this)
console.log("userSignedIn")
} else {
console.log(" No user is signed in.");
}
});
};

The problem is that this has a different meaning inside the callback, due to how you declare it.
The simplest fix is to use a fat arrow to declare the callback, same as you do elsewhere:
componentDidMount = ()=>{
console.log(this)
firebase.auth().onAuthStateChanged((user) => { // 👈
if (user) {
console.log(this)
console.log("userSignedIn")
} else {
console.log(" No user is signed in.");
}
});
This is an incredibly common problem, so I recommend reading more on it here: How to access the correct `this` inside a callback?

Related

React setState {} not setting variable

I have the following code for a main view and user login:
export class MainView extends React.Component {
constructor(){
super();
this.state = {
array: [],
user: null,
userData: {},
};
}
setUserData(user) {
if (user) {
this.setState({ userData: user.user });
console.log(user.user);
console.log (userData); /* errors in console */
} else {
console.log('userData not set');
}
}
onLoggedIn(authData) {
this.setState({ user: authData.user.Username });
/* setting localstorage key:item */
// console.log(authData);
localStorage.setItem('token', authData.token);
localStorage.setItem('user', authData.user.Username);
this.getArrayObjects(authData.token);
this.setUserData(authData);
}
using Passport to get the auth data and token. I don't get why it will log user.user in the setUserData function but will log an "undefined" error for the userData variable in the same function. Any ideas?
You are trying to access an undefined variable.
userData is present inside the state.
So you should access it with this.state.userData.
But even it you write console.log(userData);, it will print {} because in React, setState is asynchronous. Meaning, the state is not updated immediately.
If you want to check whether state has been update or not, check it like this.
this.setState({ userData: user.user }, () => {
console.log(this.state.userData);
});
The, second parameter to setState is a function that is called once state is successfully updated. So, inside there you can see the value in console.
You can't access the state directly as a var. You need to access the state, and the the properties:
console.log(state.userData);
Also, in your code, when you print state.userData, probably you will see the old value, since the setState is an async function.

How to setState inside an api function

I have this code inside a class method:
ref
.orderByValue()
.equalTo(email)
.once("value", snapshot => {
if (snapshot.exists()) {
console.log(this);
this.setState({ signedUp: true });
} else {
ref.update({ [newKey]: email });
}
});
It's going to update my Firebase database on submit, unless the user has already signed up. A typeError says this.setState is not a function. But when I console log this, the console prints out the class. Logging this.state also prints out the state.
How do I fix this? I want to update my state from inside this function.
The best solution is to use functional component.
However if you want to use class component, this is probably a binding issue.
So if this is triggered inside function named func, you should bind this function inside the constructor.
...
constructor(props) {
...
this.func = this.func.bind(this);
...
}
func() {
...
ref
.orderByValue()
.equalTo(email)
.once("value", snapshot => {
if (snapshot.exists()) {
console.log(this);
this.setState({ signedUp: true });
} else {
ref.update({ [newKey]: email });
}
});
...
}
If you don't want to bind this function, you should use arrow function.
func = () => {
...
}

Call React setState() function from async callback function

How we can call react set state from Sync callback function for example
MyClass.getAynchFunction(inputParam, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(JSON.stringify(data))
}
}
I want to set variable from 'data' object in react component state.
It's a bit of a guess because you're not specifying what exactly doesn't work, but I'm guessing you're getting something like this.setState is not a function.
That's because this isn't the React component inside your callback function. There's basically two ways to fix this
// Bind the current this to the callback function.
MyClass.getAyncFunction(
"input",
function(err, data) {
this.setState({ responseData: data });
}.bind(this)
);
// Rewrite it as an arrow function so the current this is automatically bound.
MyClass.getAyncFunction("inputParams", (err, data) => {
this.setState({ responseData: data });
});
I would go with the arrow function because it's cleaner.

How to setState in componentDidMount?

Working on this project and trying to call firebase real-time database information then setting a state after calling it so I can use it in the render. This is my code currently but its saying setState is unknown, I've tried to read up on other solutions to this problem but don't understand it, any help would be appreciated. Thanks.
componentDidMount(){
this._getLocationAsync();
firebase.database().ref('pets/').once('value', function (snapshot) {
this.setState({ testdid: snapshot.val().name })
});
}
The short answer is because this in your firebase callback refers to that function itself, rather than the component. Using an arrow function should correctly bind this to the component should fix your error:
firebase.database().ref('pets/').once('value', (snapshot) => {
this.setState({ testdid: snapshot.val().name })
});
Read up on scope in JS, particularly in regards to the this keyword. Definitely important to know, cos it has some weird behaviour sometimes.
Your callback is made in different context, you need to do :
componentDidMount(){
this._getLocationAsync();
firebase.database().ref('pets/').once('value', function (snapshot) {
this.setState({ testdid: snapshot.val().name })
}.bind(this)); // bind to current context
}
or with ES6, which i prefer
componentDidMount(){
this._getLocationAsync();
firebase.database().ref('pets/').once('value', snapshot => { // Using Fat Arrow
this.setState({ testdid: snapshot.val().name })
});
}

undefined within the react component - but not in action

Have a call to action (backend call) response is some array - getting undefined here - in few other cases where I am mapping over the array I am seeing map of undefined error as well. Is componentDidMount right place to put such calls?
I get the response back when I console log in action creator before dispatching.
componentDidMount() {
this.props.fetchData(test, foo);
console.log(this.props.responseData); //getting here undefined
}
function mapStateToProps(state) {
return {
responseData: state.abc.responseData,
};
}
Mycomp.propTypes = {
responseData: React.PropTypes.array,
fetchData: React.PropTypes.func,
};
export default connect(mapStateToProps, actions)(Mycomp);
It is undefined because the request has not been made at the time you're trying to log the response – it's async.
You can either call the action in here:
componentDidMount() {
this.props.fetchData(test, foo);
}
componentWillReceiveProps(props) {
if (props.responseData) { console.log(props.responseData); } // should be getting the data if the request works
}
or define a callback that is executed after the request was successful.
I think your fetchData() is returning Promise which is async
So you can get data from componentWillReceiveProps() which is called when ever you have new props.
componentWillReceiveProps(nextProps){
console.log(nextProps.responseData); //do whatever you want with response
}
Since componentDidMount() is called at only once. It's not reliable place to do something with your props.

Resources