Firestore error within React: Uncaught (in promise) TypeError: Cannot read properties of null (reading 'uid') - reactjs

The following is my function in which I am trying to filter notes from my Firestore collection by user.uid:
const fetchPost = async () => {
const queryConstraints = []
if (user.uid != null) queryConstraints.push(where('userID', '==', user.uid))
if (user.email != null) queryConstraints.push(where('userEmail', '==',
user.email))
const q = query(collection(db, 'notes'), ...queryConstraints)
await getDocs(collection(q))
.then((querySnapshot)=>{
const newData = querySnapshot.docs
.map((doc) => ({...doc.data(), id:doc.id }));
setNotes(newData);
console.log(notes, newData);
})
}
Yet, when I try and run this code in the browser, regardless if it is Chrome, Safari, Firefox, I am getting the following error:
Uncaught (in promise) TypeError: Cannot read properties of null
(reading 'uid')
at fetchPost (NoteList.js:66:1)
I am not sure how to fix this error, or really the right question to ask over how ask over why this this is happening.
Previously, I was using the following function:
const fetchPost = async () => {
await getDocs(collection(db, "notes"))
.where('userEmail', '==', user.email)
.then((querySnapshot)=>{
const newData = querySnapshot.docs
.map((doc) => ({...doc.data(), id:doc.id }));
setNotes(newData);
console.log(notes, newData);
})
}
I was getting the same error previously stated, but at least with this function, if I made any change to user.uid, React's hot reload would refresh the page, and it would bring in the queried data in the console, yet when I F5 the page, the data was not showing with the error message listed above.
Also, when I use the query builder in Firestore with the same parameters, I am able to pull the data I want to display, it is just not pulling/displaying as wanted in my react app.
Any help would be appreciated.

You are getting this error because your user is null.
Try to print value of user before accessing id. 👈 You'll know the value of user
Try to wrap your user.id with if(user) user.id. 👈 This should remove your erros

Related

Axios is fetching, but JSON is not displaying or being mapped

in my code i'm trying to fetch a JSON file from an URL. The URL is being fetched (I checked Network), but it's still not displayed on the website. However, the JSON data appears in the console. I think the problem is that the JSON file isn't being mapped properly.
const Blog = () => {
const [posts, setPosts] = useState([])
useEffect(() => {
const getPosts = async () => {
const response = await axios.get(`MYURL`)
setPosts(response.data.posts)
console.log(response)
}
getPosts()
}, [])
return (
<div>
{posts.map(article => {
return(
<Blog
title={article.title}
description={article.description}
url={article.url}
urltoimage={article.urltoimage}
/>
)
})}
</div>
)
}
I get the following errors when I try to run the application.
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'map')
Consider adding an error boundary to your tree to customize error handling behavior.
When I add a question mark before the mapping, like this:
{posts?.map(article =>
the errors don't come up anymore, but it still doesn't solve my problem.
Thanks.

I am losing my api data when I refresh my react app

I am using axios to fetch and retrieve data from an api. I then set the api data to some state. When I save the changes, it shows the name from index [0] of the array, as I want. However when I refresh the page, it throws an error "Cannot read properties of undefined (reading 'name')". It seems like I am losing the api data when I refresh, what am I doing wrong here? The api endpoint is madeup, as I don't want to share the real endpoint here.
const [apiData, setApiData] = useState([]);
useEffect(() => {
axios
.get("https://some-api")
.then((res) => {
setApiData(res.data);
})
.catch((error) => {
alert(error.message);
});
}, []);
return <h1>{apiData[0].name}</h1>
try it please
return <h1>{ aapiData.length && apiData[0]?.name}</h1>
It has nothing to do with refreshing the page. This will always happen on the first render for this component.
The initial state value is an empty array:
const [apiData, setApiData] = useState([]);
And you're trying to access the first element of that array:
return <h1>{apiData[0].name}</h1>
An empty array has no first element, so it throws an error.
You can use optional chaining:
return <h1>{apiData[0]?.name}</h1>
Or perhaps check if it's there before using it:
return <h1>{apiData[0] && apiData[0].name}</h1>
Or not render anything at all if the array is empty:
return apiData.length > 0 ? <h1>{apiData[0].name}</h1> : null;

CypressError: Timed out retrying: cy.its() errored because the property: 'store' does not exist on your subject

I am getting the following error on cypress when testing my application:
CypressError: Timed out retrying: cy.its() errored because the property: 'store' does not exist on your subject.
Here is the test line which is broken:
cy.window().its('store').invoke('getState').then((state) => {
expect(state.token).to.equal(tokenResponseMock.token);
});
In my code everything is working fine, i got all data on the store, no issues, but do not pass on the test due to the 'store' not found. I wonder why I am getting store error if it's working as expected. I have no clue what is going on. Does anybody can give me a light on how to solve this error?
Login.js - the function which dispatch to the store
async function handleClick() {
const { dispatchToken } = props;
const tokenInfo = await fetchToken();
localStorage.setItem('token', JSON.stringify(tokenInfo.token));
dispatchToken(tokenInfo.token);
history.push('/game');
}
Just found out what was going on.
When using cypress for testing, you need to add the following code to the store file in order to work:
if (window.Cypress) {
window.store = store;
}
Don't mix up localStorage and React store, they are two different things.
localStorage
cy.get(somthing).click()
.should(() => {
const token = localStorage.getItem('token')
expect(token).to.equal(tokenResponseMock.token)
})
React store
In React app, add store to Cypress object
// init store
if (window.Cypress) {
window.Cypress.store = store // add to Cypress not window in case of conflict
}
In test
cy.get(somthing).click()
.should(() => {
Cypress.store.getState().then(state => {
expect(state.token).to.equal(tokenResponseMock.token)
})
})

firestore getting doc data issue

I trying to get the url of an image from firebase firestore, the upload goes successfully, but when I try to get the image and display it, it gives me this error:
TypeError: undefined is not an object (evaluating 'doc.push')
This is the method how I get datas:
useEffect(() => {
const result = db.collection("homeBackground").doc("bg_img").onSnapshot(snap => {
const doc = snap.doc;
setImages(doc.push(doc => doc.data()))
});
return result;
}, []);
This is how I display the image:
{
images.push((image) => {
return (
<img src={image.imageUrl} alt=""/>
)
})
}
onSnapshot() is a kind of asynchronous Observable method. You need to check are data exist then assign to any thing you want.
.onSnapshot(snap => {
if(snap.exists()) { // Some methods returns object with .exist value/function.
setImages(snap.data())
}
});
onSnapshot(snapshoot: QuerySnapshot<DocumentData> | DocumentSnapshot<DocumentData> => ...) This is what you get depending on on what you wariong on you can get generic object of querysnapshot or DocumentSnapshot.
This method will trigger when data will change in database. It returns unsubscription which you can invoke and stop observing database changes.
const unsubscription = db.collection("homeBackground").doc("bg_img").onSnapshot(snap => ...);
// later in time
unsubscription() // this will stop invoke method above.

Why is useEffect not working here? Do I need to change the condition?

I am trying to run this code, but useEffect is not running a single time.
export default function DetailPage() {
const [post, setPost] = useState({});
const postId = useParams().postId;
console.log(postId);
useEffect(() => {
console.log("useEffect called");
const fetchPost = async () => {
const res = await axios.get(`/posts/${postId}`);
setPost(res.data);
console.log(post);
console.log("useEffect runs");
};
fetchPost();
console.log("useEffect runs 2 ");
}, [postId]);
}
Here, I am getting postId in the console, but not "useEffect run".
I have used similar code (except I am using another variable there instead of postId) in another file, and it's working there.
Please help me with this code.
Be careful, when you use setState the value of your state is changed asynchronously. So to you, it seems that the state doesn't change, but in reality, it will change.
This because when you try to print the value of a state just after the setState, its value still wasn't updated.
When you want to debug how a state changes with console log, create a separate hook that log every change.
Add something like this:
useEffect(()=>{
console.log("Post state changed!")
console.log(post);
},[post])
For what concerns the issue that your last log (console.log("useEffect runs");) is not running the only possible issues are:
postId changes are not triggering useEffect (possible reason: you are using a ref inside your useParams to store values). To check it just put a console.log before running the Axios request:
const fetchPost = async () => {
//Does this ever display your postId? If it does go to point 2.
console.log(`Trying to fetch post ${postId}`);
//Furthermore if postId can be undefined I'll wrap this request with an if
const res = await axios.get(`/posts/${postId}`);
setPost(res.data);
console.log("useEffect runs");
};
There is an uncaught error in your network request.
First tip: always put a try-catch block when awaiting an Axios response.
This will avoid missing uncaught errors.
try {
const res = await axios.get(`/posts/${postId}`);
setPost(res.data);
} catch(e) {
//Here log your error. Remember to avoid showing the log in production
}
When working with Axios I also always suggest checking the network tab of your browser to understand what is going on with your request.
I link you a post where I explain how to do it: https://stackoverflow.com/a/66232992/14106548

Resources