Reputation: 191
I'm trying to get my users's phone number for example, with a function that I import from a database.js helper file to a class component where my main navigation is:
import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { AuthStack } from "./AuthStack";
import { TabNavigator } from "./TabNavigator";
import { ProfileAuthStack } from "./ProfileAuthStack";
import firebase from "../util/firebase";
import { AppLoading } from "expo";
import { getPhone } from "../util/database";
export default class AppNavigator extends React.Component {
constructor(props) {
super(props);
this.state = {
user: "",
isLoading: false,
};
}
async componentDidMount() {
var name, email, phone;
firebase.auth().onAuthStateChanged((user) => {
if (user) {
name = user.displayName;
email = user.email;
phone = getPhone(user.uid);
console.log(name + " " + email + " " + JSON.stringify(phone));
this.setState({ user });
} else {
console.log("not logged in");
this.setState({ user: "" });
}
});
}
render() {
if (this.state.isLoading) {
return <AppLoading />;
} else {
return (
<NavigationContainer>
{this.state.user ? (
this.state.isAdmin ? (
<TabNavigator />
) : (
<ProfileAuthStack />
)
) : (
<AuthStack />
)}
</NavigationContainer>
);
}
}
}
This is my function:
import firebase from "./firebase";
//THIS IS THE FUNCTION \/
export const getPhone = function (uid) {
var phone;
var userRef = firebase.database().ref("users/" + uid);
userRef.on("value", function (snapshot) {
phone = snapshot.val().phone;
return phone;
});
};
now my console.log
looks like this:
Nikola [email protected] undefined
I can't understand why I'm getting back an undefined instead of the value itself What Am I doing wrong?
my JSON tree in the database looks like this:
{
"admins" : {
"lessons" : ""
},
"users" : {
"96GFQRlNQwQOu7zEEx7Gqp94NVq1" : {
"admin" : false,
"credit" : 0,
"injuries" : "",
"isProfileFilled" : true,
"isValid" : false,
"phone" : "123123123"
}
}
}
Upvotes: 1
Views: 294
Reputation: 598797
Data is loaded from Firebase asynchronously. Any code that needs the data needs to either be in the callback or get called from there.
Your code could be something like this:
export const getPhone = function (uid) {
var userRef = firebase.database().ref("users/" + uid);
return userRef.once("value").then(function (snapshot) {
var phone = snapshot.val().phone;
return phone;
});
};
And then:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
name = user.displayName;
email = user.email;
getPhone(user.uid).then(function(phone) {
console.log(name + " " + email + " " + JSON.stringify(phone));
this.setState({ user });
});
} else {
console.log("not logged in");
this.setState({ user: "" });
}
});
So the changes here are:
getPhone
function uses once()
instead of on
, since it only needs to get the value from the database once.then()
returned by once, and we then bubble up the return phone
by also returning return userRef...
out of getPhone
.getPhone
gets back a promise, which we handle with a then()
block. In there is the only place we can safely use phone
, so that's where we now log it and set the state.This is an incredibly common problem, so I recommend reading some of these:
async
and await
keywords that reduce the nesting.Upvotes: 2