Home > other >  Re-render a component from sibling component in React
Re-render a component from sibling component in React

Time:07-18

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 }]);
    });
  • Related