I'm working on a to-do list app in React that connects to a Firestore Database and I'm able to send the data correctly to Firebase, but my {task.name} is not displaying. The list numbers and the button are loading, but not {task.name}. The tasks are added to Firebase with the handleAdd function and the tasks are supposed to be loaded with the useEffect function. Here is the code for the main to-do.js file:
import React, { useEffect } from "react";
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { db } from "./utils/firebase";
import { collection, addDoc, Timestamp, query, orderBy, onSnapshot } from "firebase/firestore";
export default function Todo() {
const [name, setName] = useState("");
const [isDoubleClicked, setDoubleClicked] = useState(false);
const [tasks, setTasks] = useState([]);
function handleChange(event) {
event.preventDefault();
setName(event.target.value);
}
const handleAdd = async (e, id) => {
e.preventDefault();
try {
await addDoc(collection(db, 'tasks'), {
name: name,
id: uuidv4(),
completed: false,
created: Timestamp.now(),
})
} catch (err) {
alert(err)
}
}
useEffect(() => {
const q = query(collection(db, 'tasks'), orderBy('created', 'name'))
onSnapshot(q, (querySnapshot) => {
setTasks(querySnapshot.docs.map(doc => ({
id: doc.id,
data: doc.data()
})))
})
console.log(tasks);
}, [])
function handleClick(event) {
if (event.detail === 2) {
console.log("double click");
setDoubleClicked(current => !current);
event.currentTarget.classList.toggle('double-clicked');
}
}
return (
<div>
<div>
<div>
<h1>To Do List App</h1>
<p>Double click to mark an item off, click on "X" to delete an item, and drag items to reorder.</p>
</div>
<input
type="text"
value={name}
onChange={handleChange}
/>
<button
type="submit"
onClick={handleAdd}
>
Add
</button>
</div>
<ol>
{tasks.map((task => (
<li
id={task.id}
key={task.id}
completed={task.data.completed}
onClick={handleClick}
>
{task.name} <button>x</button>
</li>
)))}
</ol>
</div>
);
};
CodePudding user response:
as far as I can tell you are setting task the wrong way, instated of mapping to data stay consistent with the original uploading logic, to avoid such cases you can type your state for the sake of consistency.
useEffect(() => {
const q = query(collection(db, 'tasks'), orderBy('created', 'name'))
onSnapshot(q, (querySnapshot) => {
setTasks(querySnapshot.docs.map(doc => ({
name: doc.data().name,
id: doc.data().id,
completed: doc.data().completed,
created: doc.data().created,
})))
CodePudding user response:
I figured this out. I had to change {task.name} to {task.data.name}. I also updated the useEffect function. Here is the code:
import React, { useEffect } from "react";
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { db } from "./utils/firebase";
import { collection, addDoc, Timestamp, query, orderBy, onSnapshot } from "firebase/firestore";
export default function Todo() {
const [name, setName] = useState("");
const [isDoubleClicked, setDoubleClicked] = useState(false);
const [tasks, setTasks] = useState([]);
function handleChange(event) {
event.preventDefault();
setName(event.target.value);
}
const handleAdd = async (e, id) => {
e.preventDefault();
try {
await addDoc(collection(db, 'tasks'), {
name: name,
id: uuidv4(),
completed: false,
created: Timestamp.now(),
})
} catch (err) {
alert(err)
}
}
useEffect(() => {
const q = query(collection(db, 'tasks'), orderBy('created'))
onSnapshot(q, (querySnapshot) => {
setTasks(querySnapshot.docs.map(doc => ({
data: doc.data()
})))
})
console.log(tasks);
}, [])
function handleClick(event) {
if (event.detail === 2) {
console.log("double click");
setDoubleClicked(current => !current);
event.currentTarget.classList.toggle('double-clicked');
}
}
return (
<div>
<div>
<div>
<h1>To Do List App</h1>
<p>Double click to mark an item off, click on "X" to delete an item, and drag items to reorder.</p>
</div>
<input
type="text"
value={name}
onChange={handleChange}
/>
<button
type="submit"
onClick={handleAdd}
>
Add
</button>
</div>
<ol>
{tasks.map((task => (
<li
id={task.data.id}
key={task.data.id}
completed={task.data.completed}
onClick={handleClick}
>
{task.data.name} <button>x</button>
</li>
)))}
</ol>
</div>
);
};