function not working tho props have been passed

Viewed 59

Both of my completeTodo and removeTodo function is not working tho i have passed the props to the Todo function and in the Todo component rendered in the App.js. Anyone knows what is wrong with my two function or anything, please help me! Thank you so much!

import React, { useState } from "react";

function Todo({ todo, index, completeTodo, removeTodo }) {
  console.log("hiiii");
  return (
    <div>
      <div className={todo.isCompleted ? "line-through" : ""}>
        <p>{todo.text}</p>
      </div>
      <button onCllick={() => completeTodo(index)}>completed</button>
      <button onCllick={() => removeTodo(index)}>X</button>
    </div>
  );
}

function TodoForm({ addTodo }) {
  const [value, setValue] = useState("");

  handleSubmit = (e) => {
    e.preventDefault();
    if (!value) return;
    addTodo(value);
    setValue("");
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="add new todo"
          value={value}
          onChange={(e) => {
            setValue(e.target.value);
          }}
        />
      </form>
    </div>
  );
}

function App() {
  const [todos, setTodos] = useState([
    {
      text: "eat lunch",
      isCompleted: false
    },
    {
      text: "do homework",
      isCompleted: false
    },
    {
      text: "go to school",
      isCompleted: false
    }
  ]);

  const addTodo = (text) => {
    const newTodos = [...todos, { text }];
    setTodos(newTodos);
  };

  const completeTodo = (index) => {
    console.log("completed");
    const newTodos = [...todos];
    newTodos[index].isCompleted = true;
    setTodos(newTodos);
  };

  const removeTodo = (index) => {
    console.log("deleted");
    const newTodos = [...todos];
    newTodos.splice(index, 1);
    setTodos(newTodos);
  };

  return (
    <div>
      <div>
        {todos.map((todo, index) => {
          return (
            <Todo
              key={index}
              index={index}
              todo={todo}
              completeTodo={completeTodo}
              removeTodo={removeTodo}
            />
          );
        })}
      </div>
      <div>
        <TodoForm addTodo={addTodo} />
      </div>
    </div>
  );
}
export default App;

Sanbox link:https://codesandbox.io/s/serverless-bash-ef4hk?file=/src/App.js:0-1979

1 Answers

You are mutating the state.

const completeTodo = (index) => {
  console.log("completed");
  const newTodos = [...todos];
  newTodos[index].isCompleted = true; // <-- mutates todo object
  setTodos(newTodos);
};

const removeTodo = (index) => {
  console.log("deleted");
  const newTodos = [...todos];
  newTodos.splice(index, 1); // <-- mutates todo object
  setTodos(newTodos);
};

Along with shallow copying the array you need to also shallow copy any nested state that you are updating. The todo objects should also be new object references.

const completeTodo = (index) => {
  console.log("completed");
  setTodos((todos) =>
    // array.map to return new array
    todos.map((todo, i) =>
      i === index
        ? {
            ...todo, // shallow copy old todo object
            isCompleted: true
          }
        : todo
    )
  );
};

const removeTodo = (index) => {
  console.log("deleted");
  // array.filter to return new array
  setTodos((todos) => todos.filter((_, i) => i !== index));
};

Fix the buttons in the Todo, they aren't using the correct event handler.

<button onCllick={() => completeTodo(index)}>completed</button>
<button onCllick={() => removeTodo(index)}>X</button>

should be

<button onClick={() => completeTodo(index)}>completed</button>
<button onClick={() => removeTodo(index)}>X</button>

Edit function-not-working-tho-props-have-been-passed

Related