Reputation: 15
I am trying to retrieve the data from firebase realtime database and then pass it another function. But it throws an error saying TypeError: undefined is not an object (evaluating 'notesList.map')
function NotesList() {
const[notesList, SetNotesList] = useState();
useEffect(() => {
const NoteRef = firebase.database().ref('localnotes-data');
NoteRef.on('value', (snapshot)=> {
const notes = snapshot.val();
const container = [];
for(let id in notes){
container.push({id, ...notes[id] });
}
if (container){
SetNotesList(container);
}
}, []);
})
console.log(notesList);
return (
<View style={styles.list}>
<ScrollView>
<Search />
<Add />
{notesList.map((note) => (<Note text = {text} date = {date}/>))}
</ScrollView>
</View>
)
}
const styles = StyleSheet.create({
list: {
marginTop: 0,
marginBottom: 145,
}
})
export default NotesList
This is console.log(notesList)
Upvotes: 0
Views: 244
Reputation: 507
Because noteList
is undefined -> const[notesList, SetNotesList] = useState();
So check that noteList exists to call map when you asynchronous fetch is finished.
You can also initialise you noteList like so -> const[notesList, SetNotesList] = useState([]);
The following code should work tho.
...
return (
<View style={styles.list}>
<ScrollView>
<Search />
<Add />
{notesList && notesList.map((note) => (<Note text = {text} date = {date}/>))}
</ScrollView>
</View>
)
}
...
Upvotes: 1
Reputation: 26306
As an alternative to @Dharmaraj's answer, you can also introduce a "loading" variable like so:
Note: Make sure to take a look at the other changes like some variable names, using DataSnapshot#forEach()
to maintain the order from the query, detaching the snapshot listeners, snapshot error-handling and making sure the key
property is set in the map()
function.
let renderCount = 0; // just for debugging, remove it later
function NotesList() {
const [notesList, setNotesList] = useState();
const notesLoading = notesList === undefined;
useEffect(() => {
const notesQueryRef = firebase.database()
.ref('localnotes-data');
// you can add `orderByChild()`, etc. to the above query
const listener = notesQueryRef.on(
'value',
(snapshot) => {
const notesArray = [];
snapshot.forEach(noteSnapshot =>
const id = noteSnapshot.key;
notesArray.push({
id: noteSnapshot.key,
...noteSnapshot.val()
});
);
setNotesList(notesArray);
},
(error) => {
// TODO: Handle errors better than this
console.error("Failed to get notes: ", error);
}
);
// return cleanup function
return () => {
notesQueryRef.off('value', listener);
};
}, []);
// just for debugging, remove it later
console.log({
renderCount: ++renderCount,
notesLoading,
notesList
});
return (
<View style={styles.list}>
<ScrollView>
<Search />
<Add />
{notesLoading
? <Spin tip="Loading..." key="loading" />
: notesList.map(note => (<Note
text={note.text}
date={note.date}
key={note.key}
/>));
}
</ScrollView>
</View>
)
}
const styles = StyleSheet.create({
list: {
marginTop: 0,
marginBottom: 145,
}
})
export default NotesList
Upvotes: 1
Reputation: 50930
I think that's because initial state of notesList
is undefined. Try setting that to an empty array.
const [notesList, SetNotesList] = useState([]);
^^
Now notesList
is defined and you can run the map()
method on it.
Upvotes: 0