1

So this is really strange

this is my code when it works

useEffect(() => { // Alleen preview async function getTracksData() { let TrackData = await firebase .firestore() .collection('TrackScreen') .doc('LeerjarenData') .get(); if (!TrackData.exists) { console.log('Geen data') } else { let TrackDatav2 = TrackData.data(); setTrackScreenData(TrackDatav2) } } getTracksData() // SNAPSHOT USER DATA db.collection("users").doc(currentUserUID) .onSnapshot((doc) => { setUserData(doc.data()); }); }, []) console.log(trackscreenData.data) 

this works perfectly but when i change my console to

console.log(trackscreenData.data[0] 

it gives me this error

TypeError: undefined is not an object (evaluating 'trackscreenData.data[0]') 

then when i change my console again to

console.log(trackscreenData.data) 

it works and when i change i back to

console.log(trackscreenData.data[0]) 

and save the changes it gives me the data i want

what am i doing wrong?

2 Answers 2

1

In short, you are trying to use the data from your asynchronous call before its ready.

To handle the case where your data hasn't finished loading, you should use:

console.log(trackscreenData && trackscreenData.data) 

Based on the patterns in your code, you have these lines at the top of your component.

const { currentUserID } = useAuth(); // or similar const [userData, setUserData] = useState(); const [trackscreenData, setTrackScreenData] = useState(); // NOTE: check for typos: "trackscreenData" !== "trackScreenData" 

On the first render of your code, trackscreenData will be undefined because you haven't passed an initial state into the useState() method.

const [trackscreenData, setTrackScreenData] = useState(/* initial state */); 
// `trackscreenData` initially set to `null` const [trackscreenData, getTracksData] = useState(null); // `trackscreenData` initially set to `[]` const [trackscreenData, getTracksData] = useState([]); // `trackscreenData` initially set to the result of the function, // an array containing the elements 0 through 99. The function is // only executed once to set the first value. // trackscreenData = [0, 1, 2, 3, ... , 97, 98, 99]; const [trackscreenData, getTracksData] = useState(() => { Array.from({length: 100}) .map((_, i) => i); } 

When React executes your code, any calls to setters returned from useState calls (e.g. setTrackScreenData) are queued. Only once your code has finished executing, are they evaluated and any new renders triggered.

const [count, setCount] = useState(0); // `count` is initially set to `0` useEffect(() => { if (count < 10) { setCount(count + 1); } }) console.log(count); console.log("rendered"); // Console logs: // > "0" // > "rendered" // > "1" // > "rendered" // > ... // > "9" // > "rendered" // > "10" // > "rendered" 

Your fetch of user data should be in its own useEffect call and should return its unsubscribe function:

useEffect(() => { if (!currentUserUID) { setUserData(null); // user not signed in return; } // SNAPSHOT USER DATA return db.collection("users") // <- note the return here .doc(currentUserUID) .onSnapshot((doc) => { setUserData(doc.data()); }); }, [currentUserUID]); 
useEffect(() => { let disposed = false; // Alleen preview async function getTracksData() { let TrackData = await firebase .firestore() .collection('TrackScreen') .doc('LeerjarenData') .get(); if (disposed) return; // component was removed, do nothing if (!TrackData.exists) { console.log('Geen data') } else { let TrackDatav2 = TrackData.data(); setTrackScreenData(TrackDatav2) } } getTracksData() .catch((err) => console.error(err)); // don't forget to handle errors! return () => disposed = true; // ignore result if component disposed }, []); 
Sign up to request clarification or add additional context in comments.

Comments

0

You are specifying the document ID by .doc(...) and hence you are getting a DataSnapshot as the response which is not an array.

If you were using queries like .where(...) then it would have returned a QuerySnapshot.

A QuerySnapshot contains zero or more DocumentSnapshot objects representing the results of a query. The documents can be accessed as an array via the docs property or enumerated using the forEach method. The number of documents can be determined via the empty and size properties.

So if you are fetching only a single document that way, you don't need to access the doc by [0] as it is not an array. You can simply access the data by dataSnapshot.data()

Although I can't see where is trackscreenData defined?

useEffect(() => { // Alleen preview async function getTracksData() { let TrackData = await firebase .firestore() .collection('TrackScreen') .doc('LeerjarenData') .get(); if (!TrackData.exists) { console.log('Geen data') } else { let TrackDatav2 = TrackData.data(); setTrackScreenData(TrackDatav2) console.log(trackScreenData) } } }, []) 

2 Comments

i have tried it but it doesn't work for me there was a wrong console in my question. i now have changed it
@SandervanMaastricht please try copying my code above

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.