Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React JS – Can't maintain and render the state values after onclick

I followed a tutorial to make a todo using functional component, where I am facing issue when I am trying to delete or mark as complete the item in todo list. I have tried to make use of the prev state values in both of the deleteHandler and completeHandler. The values in the list is working as expected but when I am deleting one item from the list, the whole state values are getting destroyed. I have wrote down the component where I am having the deleteHandler and completeHandler and also the other two components. Anyone please guide me what I am missing in the code. Thanks in advance.

I am having three components(Form, TodoList and Todos). Form component is the parent component from there only I am passing the state value as props to TodoList and Todos component.

Todo Component:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

const Todo = ({ text, todo, todos, setTodos }) => {
  const deleteHandler = (prevState) => {
    setTodos(todos.filter((el) => el.id !== todo.id));
    // console.log(todo);
  };

  const completeHandler = () => {
    setTodos(
      todos.map((item) => {
        if (item.id === todo.id) {
          return {
            ...item,
            completed: !item.completed,
          };
        }
        return item;
      })
    );
  };

  return (
    <div className="todo">
      <li className={`todo-item ${todo.completed ? "completed" : ""}`}>
        {text}
      </li>
      <button onClick={completeHandler} className="complete-btn">
        <i className="fas fa-check"></i>
      </button>
      <button onClick={deleteHandler} className="trash-btn">
        <i className="fas fa-trash"></i>
      </button>
    </div>
  );
};

export default Todo;

TodoList Component:

const TodoList = ({ todos, setTodos, filterTodos }) => {
  // console.log("prp", todos);

  return (
    <div className="todo-container">
      <ul className="todo-list">
        {todos && todos.length
          ? filterTodos.map((todo) => (
              <Todo
                setTodos={setTodos}
                todos={todos}
                todo={todo}
                key={todo.id}
                text={todo.text}
                id={todo.id}
              />
            ))
          : ""}
      </ul>
    </div>
  );
};

export default TodoList;

Form Component:

const Form = () => {
  const [inputText, setInputText] = useState("");
  const [todos, setTodos] = useState([]);
  const [status, setStatus] = useState("all");
  const [filterTodos, setFilterTodos] = useState([]);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const filterHandler = () => {
    switch (status) {
      case "completed":
        setFilterTodos(todos.filter((todo) => todo.completed === true));
        break;
      case "incompleted":
        setFilterTodos(todos.filter((todo) => todo.completed === false));
        break;
      default:
        setFilterTodos(todos);
        break;
    }
  };

  useEffect(() => {
    filterHandler();
  }, [todos, status, filterHandler]);

  const inputHandler = (e) => {
    setInputText(e.target.value);
  };

  const submitTodohandler = (e) => {
    e.preventDefault();
    setTodos([
      ...todos,
      { text: inputText, completed: false, id: Math.random() * 1000 },
    ]);
    setInputText(" ");
  };

  const statusHandler = (e) => {
    console.log(e.target.value);
    setStatus(e.target.value);
  };
  return (
    <form>
      <input
        value={inputText}
        onChange={inputHandler}
        type="text"
        className="todo-iput"
      />
      <button className="todo-button" type="submit" onClick={submitTodohandler}>
        <i className="fas fa-plus-square"></i>
      </button>
      <div className="select">
        <select name="todos" className="filter-todo" onChange={statusHandler}>
          <option value="all">All</option>
          <option value="completed">completed</option>
          <option value="incompleted">Incompleted</option>
        </select>
      </div>
      <TodoList setTodos={setTodos} todos={todos} filterTodos={filterTodos} />
    </form>
  );
};

export default Form;

>Solution :

Since your TodoList is inside the form tag you’ll need to add preventDefault() in both deleteHandler and completeHandler to avoid page refresh.

codesandbox

const deleteHandler = (e) => {
    e.preventDefault();
    setTodos(todos.filter((el) => el.id !== todo.id));
    // console.log(todo);
  };

const completeHandler = (e) => {
    e.preventDefault();
    setTodos(
      todos.map((item) => {
        if (item.id === todo.id) {
          return {
            ...item,
            completed: !item.completed
          };
        }
        return item;
      })
    );
  };
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading