Still_Learning
Still_Learning

Reputation: 229

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:

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;

Upvotes: 0

Views: 144

Answers (1)

Girgetto
Girgetto

Reputation: 1086

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;
      })
    );
  };

Upvotes: 1

Related Questions