'Issue with deleting a doc in firestore with react native
I am building a todo list application with expo/react native and have added a delete button for each looped todo. However, once you click it a type error of occurs:
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_n9.indexOf')]
code:
import React, { useEffect } from 'react';
import {useState} from "react"
import { SafeAreaView, Text, View, Button, TouchableOpacity, Modal, StyleSheet,Pressable, TextInput,ImageBackground, Image, ScrollView, } from 'react-native';
import { collection, doc, setDoc, query, getDocs, onSnapshot, addDoc, orderBy, limit, Timestamp, where, deleteDoc} from "firebase/firestore";
import {db} from "../firebase"
import { auth } from '../firebase';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AntDesign } from '@expo/vector-icons';
import { Feather } from '@expo/vector-icons';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Checkbox from 'expo-checkbox';
import {signPlsOut} from "../firebase"
import { Appearance } from 'react-native';
import EmojiSelector from 'react-native-emoji-selector'
export const Dashboard = () => {
const image = { uri: "https://cdn.discordapp.com/attachments/901614276748402820/946157600041476176/Screen_Shot_2022-02-23_at_4.32.16_PM.png" };
const {uid, photoURL, displayName, email} = auth.currentUser;
const [modalVisible, setModalVisible] = useState([]);
const [modalVisibleImage, setModalVisibleImage] = useState([])
const [projects, setProjects] = useState([])
const [desc, setDesc] = useState("");
const [title, setTitle] = useState("");
const todosref = collection(db, 'todosref')
const [isChecked, setChecked] = useState(false);
const date = new Date().toLocaleString();
const [emojiuser, setEmojiUser] = useState("")
const [show, setShow] = useState(false);
const onClick = emoji => {
console.log(emoji);
};
const colorScheme = Appearance.getColorScheme();
if (colorScheme === 'dark') {
// Use dark color scheme
}
const [profilename, setProfileName] = useState("")
const shadowColors = ["#FFD6A7", "#FF92B3", "#59F5D1", "#C1F1FE", "#A498FE"]
const shadowColor = shadowColors[Math.floor(Math.random()*shadowColors.length)];
useEffect(() => {
const getData = async () => {
const q = await query(todosref, where('uid', '==', uid), orderBy("createdAt"))
onSnapshot(q, (snapshot) => {
let todos = []
snapshot.forEach((doc) => {todos.push(doc.data())})
setProjects(todos)
})
}
getData()
}, [])
async function handleAddTask () {
try {
await addDoc(todosref, {
title: title,
desc: desc,
createdAt: Timestamp.fromDate(new Date()),
uid: uid,
backgroundColor: shadowColor,
emoji: emojiuser,
checked: false
})
setTitle("")
setDesc("")
setModalVisible(false)
setEmojiUser("")
}
catch(error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
// ADD THIS THROW error
throw error;
}
}
const deleteDoc = async (id) => {
try {
const userDoc = doc(db, "todosref", id);
deleteDoc(userDoc);
} catch(error){
alert(error)
}
};
return (
<>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
setModalVisible(!modalVisible);
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Add task:</Text>
<View style={{marginBottom: 20}}>
<TextInput placeholder='title' value={title} onChangeText={(text) => setTitle(text)} style={{marginBottom: 20, fontSize: 20}}></TextInput>
<TextInput placeholder='description' value={desc} onChangeText={(text) => setDesc(text)}></TextInput>
</View>
<Text style={{fontWeight: "700", fontSize: 20, marginBottom: 20}}>Emoji:</Text>
<EmojiSelector onEmojiSelected={emoji => setEmojiUser(emoji)} showTabs={false} showSearchBar={false} columns="10" />
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={handleAddTask}
>
<Text style={styles.textStyle}>submit task</Text>
</Pressable>
<Pressable
style={[styles.cancel]}
onPress={() => setModalVisible(!modalVisible)}
>
<Text style={{color: "#000", fontSize: 20}}>Cancel</Text>
</Pressable>
</View>
</View>
</Modal>
<Modal
animationType="slide"
transparent={true}
visible={modalVisibleImage}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
setModalVisible(!modalVisible);
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Change PFP</Text>
<View style={{display: "flex", flexDirection: "row", justifyContent: "space-between", marginBottom: 20}}>
<Image source={{uri: "https://cdn.discordapp.com/attachments/926690547253534740/952329304056946758/Screen_Shot_2022-03-12_at_5.16.26_PM.png"}}style={{
height: 60,
width: 60,
marginRight: 20,
borderRadius: 40
}}></Image>
<Image source={{uri: "https://cdn.discordapp.com/attachments/926690547253534740/952329352421449828/Screen_Shot_2022-03-12_at_5.16.46_PM.png"}}style={{
height: 60,
width: 60,
marginRight: 20,
borderRadius: 40
}}></Image>
<Image source={{uri: "https://cdn.discordapp.com/attachments/926690547253534740/952329388077228052/Screen_Shot_2022-03-12_at_5.16.56_PM.png"}}style={{
height: 60,
width: 60,
borderRadius: 40
}}></Image>
</View>
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModalVisibleImage(!modalVisibleImage)}
>
<Text style={styles.textStyle}>Cancel</Text>
</Pressable>
</View>
</View>
</Modal>
<SafeAreaView style={{
flex: 1,
display: "flex",
justifyContent: 'space-between',
margin: 20,
flexDirection: "column",
}}>
<View style={{
flex: 1,
marginTop: 20,
}}>
<View style={{marginBottom: 20, display: "flex", flexDirection: "row", justifyContent: "space-between"}}>
<View style={{display: "flex", flexDirection: "row"}}>
<Pressable onPress={() => setModalVisibleImage(true)}>
<Image source={{uri: "https://cdn.discordapp.com/attachments/856542608171073616/947245168191496212/Screen_Shot_2022-02-26_at_4.33.30_PM.png"}} style={{width: 50, height: 50}}></Image>
</Pressable>
<View style={{marginLeft: 20, display: "flex", justifyContent: "space-between"}}>
<TextInput style={{fontSize: 17, fontWeight: "700"}} placeholder={email} placeholderTextColor="#9D9EA2" />
<Text style={{color: "grey", fontSize: 15}}>Good Day 👋🏼</Text>
</View>
</View>
<View style={{display: "flex", flexDirection: "row", alignItems: "center"}}>
<AntDesign name="search1" size={24} color="black" />
<Feather name="bell" size={24} color="black" style={{marginLeft: 10}}/>
</View>
</View>
<View style={{display: "flex", flexDirection: "row", marginBottom: 20, alignSelf: "center"}}
><Text style={{marginLeft: 30, fontSize: 27, fontWeight: "700", marginRight: 10}}>{new Date().toLocaleString('en-US', {
weekday : 'long'
})}</Text>
<Text style={{marginRight: 5, fontSize: 27, fontWeight: "700"}}>
{new Date().toLocaleString('en-US', {
month : 'long'
})},</Text>
<Text style={{ fontSize: 27, fontWeight: "700", marginRight: 30}}>{new Date().getDate()}th</Text>
</View>
<ScrollView style={{
flex: 1, padding: 10, borderRadius: 20, marginBottom: 20,
backgroundColor: "#F5F4F7", position: "relative"
}}>
<Text style={{
fontSize: 20,
fontWeight: "700"
}}>Goals for Today</Text>
<View style={{display: "flex", flexDirection: "column"}}>
{projects.map((doc, key) => (
<View key={key} style={{
backgroundColor: doc.backgroundColor,
padding: 20,
marginTop: 20,
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
borderWidth: 1,
borderRadius: 20,
borderColor: 'transparent',
borderBottomWidth: 0,
shadowColor: doc.backgroundColor,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 1,
shadowRadius: 20,
elevation: 3,
flex: 1,
}}>
<View style={{display: "flex", flexDirection: "row", alignItems: "center"}}>
<Text style={{}}>{doc.emoji}</Text>
<Text style={{
fontSize: 26,
color: "#fff",
fontWeight: "700",
marginLeft: 10
}}>{doc.title}</Text>
</View>
<View>
<Text style={{
fontSize: 18 , color: "#fff",marginLeft: 34
}}>{doc.desc}</Text>
</View>
<View>
<View>
<Button title='Delete todo' onPress={(e) => deleteDoc(doc.id)}></Button>
</View>
</View>
</View>
))}
</View>
<View style={{backgroundColor: "#4630EB", borderRadius: "20", padding: 10, alignSelf: "center", bottom: 0, left: 0, right: 0, marginTop: 100}}>
<Button title='Sign Out' onPress={signPlsOut} color="#fff" style={{
color: "#fff"
}}></Button>
</View>
</ScrollView>
</View>
<View style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
}}>
<TouchableOpacity >
<Pressable
onPress={() => setModalVisible(true)}>
<AntDesign name="pluscircle" size={50} color="#8BF45B" />
</Pressable>
</TouchableOpacity>
</View>
</SafeAreaView>
</>
);
};
the main issue of the code is the
const deleteDoc = async (id) => {
try {
const userDoc = doc(db, "todosref", id);
deleteDoc(userDoc);
} catch(error){
alert(error)
}
};
and
<View>
<View>
<Button title='Delete todo' onPress={(e) => deleteDoc(doc.id)}></Button>
</View>
</View>
Any thoughts on how to fix it?
Solution 1:[1]
You would get that kind of error if you are passing a value of undefined to your userDoc variable. On your useEffect:
const getData = async () => {
const q = await query(todosref, where('uid', '==', uid), orderBy("createdAt"))
onSnapshot(q, (snapshot) => {
let todos = []
snapshot.forEach((doc) => {
// doc.data() doesn't have the document's ID by default.
todos.push(doc.data())})
setProjects(todos)
})
}
You're pushing the document's data to the todos array which does not include the document ID (unless you have an ID field on your document). You could instead use the .map() method to add the document ID and set it on the projects state. See code below:
useEffect(() => {
const getData = async () => {
const q = await query(todosref, where('uid', '==', uid), orderBy("createdAt"))
onSnapshot(q, (snapshot) => {
// Includes the document's ID.
const documents = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
setProjects(documents)
})
}
getData()
}, [])
Also, as pointed out by @guiwme5, for best practice, don't use the same name for your function as it will be recognized as a recursive function. I would suggest changing it to something like deleteDocument:
const deleteDocument = async (id) => {
try {
const userDoc = doc(db, "todosref", id);
deleteDoc(userDoc);
} catch(error){
alert(error)
}
};
View:
<View>
<Button title='Delete todo' onPress={(e) => deleteDocument(doc.id)}></Button>
</View>
For more information, check out this documentation:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Marc Anthony B |
