'Firebase not returning ID in useCollectionData
I'm trying to make a simple firebase to-do app. I can write todos, no problem. However, when I try to delete a todo or mark one as complete, it seems the id is undefined, and firebase can't find the to-do in question. How can I correct this? For context, I am following this tutorial: https://www.youtube.com/watch?v=cuvP4h6O2x8&t=755s
Code:
import "../App.css";
import {useState} from "react";
import {auth, firestore} from "../firebase";
import firebase from "../firebase";
import {useCollectionData} from "react-firebase-hooks/firestore";
const Todos = () => {
const [todo, setTodo] = useState("");
const todosRef = firestore.collection(`users/${auth.currentUser.uid}/todos`);
const [todos] = useCollectionData(todosRef, { idField: "id" });
const signOut = () => auth.signOut();
const onSubmitTodo = (event) => {
event.preventDefault();
setTodo("");
todosRef.add({
text: todo,
complete: false,
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});
};
return (
<>
<header>
<button onClick = {signOut}>Sign Out</button>
</header>
<main>
<form onSubmit = {onSubmitTodo}>
<input
required
value = {todo}
onChange = {(e) => setTodo(e.target.value)}
placeholder="what's next?"
/>
<button type="submit"> Add </button>
</form>
{todos && todos.map((todo)=> <Todo key={todo.id} {...todo} />)}
</main>
</>
);
};
const Todo = ({ id, complete, text}) => {
const todosRef = firestore.collection(`users/${auth.currentUser.uid}/todos`);
const onCompleteTodo = (id, complete) =>
todosRef.doc(id).set({ complete: !complete }, { merge: true });
const onDeleteTodo = (id) => todosRef.doc(id).delete();
return (
<div key={id} className="todo">
<button
className={`todo-item ${complete ? "complete" : ""}`}
tabIndex="0"
onClick={()=> onCompleteTodo(id, complete)}
>
{text}
</button>
<button onClick={() => onDeleteTodo(id)}>x</button>
</div>
);
};
export default Todos;
Solution 1:[1]
React Firebase Hooks v5 matches Firebase 9 and above, in which you should use the FirestoreDataConverter interface.
See the documentation.
The examples use TypeScript, but in your case something like this should work, applying withConverter and your custom converter right after getting the collection:
const converter = {
toFirestore(post) {
return {
text: post.text,
}
},
fromFirestore(snapshot, options) {
const data = snapshot.data(options)
return {
id: snapshot.id,
text: data.text,
}
},
}
const todosRef = firestore
.collection(`users/${auth.currentUser.uid}/todos`)
.withConverter(converter);
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 | alotropico |
