I am currently learning react and I am trying to make a ToDo App. Now I am having a problem when I add a new task in the list. I can successfully add an item in the list when I click the add button, the json file where I store each todo is also update, but the problem is the text wont show.
This is what it looks like. The text will only show if I refresh the page.
Here is my <Home/>
component
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import AddTask from "./AddTask";
import TaskList from "./TaskList";
import useFetch from "./useFetch";
const Home = () => {
const {
data: todo,
setData: setTodo,
isPending,
error,
} = useFetch("http://localhost:8000/tasks");
useEffect(() => {
if (todo) setTodo(todo);
}, [todo]);
return (
<div className="home">
<AddTask setTodo={setTodo} />
{error && <div>Failed to fetch data.</div>}
{isPending && <div>Loading...</div>}
{todo && <TaskList todo={todo} setTodo={setTodo} />}
<Link to="/trashbin" className="history">
View History
</Link>
</div>
);
};
export default Home;
Here is my <AddTask/>
component.
import { useState } from "react";
const AddTask = ({ setTodo }) => {
const [task, setTask] = useState("");
const [isPending, setIsPending] = useState(false);
const handleClick = (e) => {
e.preventDefault();
setIsPending(true);
const todo = { task };
fetch("http://localhost:8000/tasks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(todo),
}).then(() => {
setIsPending(false);
setTodo((prev) => [...prev, task]);
});
setTask("");
};
return (
<form className="new-task" onSubmit={handleClick}>
<input
className="input"
type="text"
required
placeholder="Add new task..."
value={task}
onChange={(e) => setTask(e.target.value)}
/>
<button className="add-task">
<i className="fa-solid fa-plus fa-2x"></i>
</button>
</form>
);
};
export default AddTask;
And here is my <Tasklist/>
component which will display the task list.
import $ from "jquery";
import { useEffect, useState } from "react";
const TaskList = ({ todo, setTodo }) => {
const [todos, setTodos] = useState("");
return (
<div className="tasks">
<ul>
{todo.map((todo) => (
<li className="task" id={todo.id} key={todo.id}>
<input type="checkbox" className="checkbox" />
<p className="task-name paragraph">{todo.task}</p>
<input
type="text"
className="task-name edit-task"
value={todos}
onChange={(e) => setTodos(e.target.value)}
/>
<button className="edit button">
<i className="fa-solid fa-edit"></i>
</button>
<button
onClick={() => handleDelete(todo.id, todo.task)}
className="delete button"
>
<i className="fa-solid fa-trash-can"></i>
</button>
</li>
))}
</ul>
</div>
);
};
export default TaskList;
CodePudding user response:
setTodo((prev) => [...prev, task]);
You set a new task as a string in AddTask
, but in fact, it's an object in TaskList
<p className="task-name paragraph">{todo.task}</p>
...
<button
onClick={() => handleDelete(todo.id, todo.task)}
className="delete button">
<i className="fa-solid fa-trash-can"></i>
</button>
For the fix, you should make a new task from the response
fetch("http://localhost:8000/tasks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(todo),
}).then((response) => {
setIsPending(false);
setTodo((prev) => [...prev, { id: response.id, task: response.task }]);
});
If your response returns no data, you can try to add a new task with the current task state along with a fake id (because you don't have it in the response)
fetch("http://localhost:8000/tasks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(todo),
}).then((response) => {
setIsPending(false);
setTodo((prev) => [...prev, { id: task, task: task }]);
});