I'm trying to add information to the document of the user currently logged in.
I have the following code snippet of code in my component -
console.log("user", auth.currentUser?.uid);
useEffect(() => {
if (productId) {
db.collection("users")
.doc(auth.currentUser?.uid)
.collection("cart")
.doc(productId)
.onSnapshot((snapshot) => setProduct(snapshot.data()));
}
}, []);
Here,
const auth = firebase.auth();
The console log actually gives me the uid of the user but the hook below produces an errror -
FirebaseError: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: undefined
I have used the same approach in another component to add data and it works fine.
Why does this happen? Thanks in advance.
auth.currentUser is going to be null if there is no user signed in at the moment it was accessed. Your code is blindly ignoring this possibility by using the ? operator to "safely" access its properties anyway. When you use ?, if the prior expression is "falsy", the entire expression becomes undefined. Your code should instead check for null before assuming there is an object to use.
const currentUser = auth.currentUser
if (currentUser) {
const uid = currentUser.uid;
}
else {
// what do you want to do if there is no one signed in?
}
If you need to wait until a user is actually signed in, you should use an auth state observer to get a callback that tells you when the user object is available.
See also: Typescript the safe navigation operator ( ?. ) or (!.) and null property paths
Related
I've been trying to create a .env variable where initially it will be empty but after login process it will store the data to the .env variable for further work, but unfortunately, I am not able to do so.
Before I put my code example, I would like to have some suggestions!!
Yea, in the login process I'm using session storage to store the user token. So, will it be a good work to store the user data into a .env file and later access it for future use or should I just call getToken function every time I need the token to verify if the user is logged in.
login.js:
const getToken = () => {
const tokenString = sessionStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken?.token
}
const saveToken = (userData) => {
sessionStorage.setItem('token', JSON.stringify(userData));
setToken(userData)
}
Tried different techniques to make it work, but I just couldn't get the data from the .env file.
Watched many different YouTube videos and did exactly like them but it was all in vain.
I checked multiple timed if there is any type or bug in my code or not! There was no error. I was getting the token after successful login and by default it was returning null. I was storing the token only when the user login successfully so that no garbage value gets inserted into the value.
Here's my logic:
const handleSubmit = async function (e) {
e.preventDefault();
const response = await loginUser(user);
if (response.status === 200) {
setToken(response.data);
process.env.REACT_APP_USER_TOKEN=response.data;
navigate("/");
} else {
console.error(response)
}
}
ENV files are used to store sensitive Api keys or secrets. which can only be read by the code when needed.
Storing user data in .env file is not the right way. If your user data should not be available easily in frontend, try encryption and store the encryption key in .env file or backend.
I'm new to React-native so if there is a misunderstanding please be super clear and treat me as if I have never seen React-native before.
I have the app so that when you press on a button it will send you into an Auth0 flow where you can log in to the app. This seems working. If I log out the access token directly in the callback I am successful in getting it at the credentials.accessToken variable/location. However, when I am trying to set the state of the accessToken variable I get back null when I try to log it out to the screen via an alert or even via console.log. What am I doing wrong to cause this? I tried searching SO and google but both seem to show this as the right way of doing it.
Code:
const [accessToken, setAccessToken] = useState(null)
const onLogin = () => {
auth0.webAuth
.authorize({
scope: 'openid profile email'
})
.then(credentials => {
setAccessToken(credentials.accessToken)
Alert.alert('Access token: ', accessToken)
})
.catch(error => console.log(error)) // Eventually send this to backend for crash reporting
}
This is probably a case of a state not updating immediately. Try to use a useRef() instead of a useState(https://www.w3schools.com/react/react_useref.asp). If the problem is solved the issue was with the fact that states are updated asynchronously and hence it was not set to its most recent value (the value you expected) when you console logged it.
I am using react-query-firebase library to make a query to a document.
According to documentation this is how you make a query:
const ref = doc(firestore, 'users', id);
const product = useFirestoreDocument(["users", id], ref);
Everything works when I manually set id like this:
const id = "pW5CizOJOpXezr5lGGsh";
However I want to set the uid dynamically and I am using auth state hook as well:
const user = useAuthUser(["user"], auth);
const ref = doc(firestore, "users", user.data.uid);
the problem is that on page load user initializes as undefined and I need to wait for a split second for user.data.uid to populate and because of that I am getting TypeError: Cannot read property 'indexOf' of undefined
is there a way to skip making a query until user has finished loading and only then make a query.
with react-query, you would usually just disable the query until you have all the dependencies via the enabled property:
useQuery(["users", id], ref, { enabled: Boolean(id) }
This is documented in the dependent queries section of the docs.
can someone please help me to retrieve username from user ID and send a message to the chat with that ID?
if (message.content.startsWith(prefix)) {
const [CMD_NAME, ...args] = message.content
.trim()
.substring(prefix.length)
.split(/\s+/);
if (CMD_NAME === "getid") {
const getid1 = new MessageEmbed()
.setDescription("❗️ | Please tag the member to retrieve the ID!")
.setColor(10181046);
if (args.length === 0) return message.reply(getid1);
const username = client.guilds.cache.get('<GUILD ID>');
const userid = client.users.cache.find(username => username.tag === 'Someone#1234').id
message.channel.send(`${username} id is ${userid}`);
}
}
});
When I type the command "d!getid #Username", it shows me this error:
C:\Users\USER\Desktop\DiscordBotas\index.js:152 const userid = client.users.cache.find(username => username.tag === 'Someone#1234').id TypeError: Cannot read property 'id' of undefined at Client. (C:\Users\USER\Desktop\DiscordBotas\index.js:152:90)
You are creating a lambda of a variable that you just defined above the actual lambda, this could probably mess with your code.
The const username = client.guilds.cache.get('<GUILD ID>'); is wrong.
The fetching of the userId should probably work if you fix the line above it.
You are trying to get the user the wrong way. Firstly, why are you trying to match a user's tag with a guild? Maybe you think guild.cache has users? Well actually, this is client.guilds.cache, which only has guilds in it, and it returns a guild, not a user. Secondly, to get a user, you can try this method:
const user = client.users.cache.find(u => u.tag === 'SomeUser#0000')
console.log(user.id);
Below is code to get user by ID, but it probably won’t help with this, considering you would already have access to the ID
const user = client.users.cache.get("<UserID>");
console.log(user);
Also, you should add code to see if user isn’t found (client can’t find user with the condition). Here is some code to check that:
//... the find user code I put
if(!user) return message.reply('User could not be found');
message.channel.send(user.id);
I can return a query's data using useQuery no problem. I'm trying to retrive a user with the following query but when accessing data.user my app throws an error to say data is undefinded.
const userQuery = gql`
{
user {
id
email
}
} `;
export default NavWrapper = () => {
const { loading, error, data } = useQuery(userQuery);
console.log(data);
if (loading) return <ActivityIndicator size="large"/>
if (!data) return <Login/>;
return <Navigator/>;
}
The above works fine and retrives the user within an object, but I need to render the login comp based on the actual user rather than the data wrapper. Any ideas? must be simple...
Likely you have unsafe property access and are trying to use data.user before the query finishes. Essentially, your code is operating under the assumption data will always be present, whereas the nature of a query is such that there is a beginning unqueried state in which there is no data, followed by a loading state during which the query is being made and no data is available, followed by a somewhat final state in which data is made available. Your code should be prepared for all the states.
To account for these situations, you should use safe property access like so:
const user = data ? data.user : null
Alternatively, you can use a safe property access lib like idx:
const user = idx(data, _ => _.user) || null
Further, you'll want to make sure any components consuming your user data are prepared for the case in which the user is not available to them.
Note: data.user isn't referenced any where in the code you linked. It'll be helpful to know exactly where you're calling it (e.g. in body of NavWrapper vs Login or elsewhere).