reactjs 为什么不删除待办事项?

im9ewurl  于 2022-12-22  发布在  React
关注(0)|答案(6)|浏览(122)

我正在为我正在学习的课程做一个教程。我正在做的实验是创建一个待办事项应用程序。我正在进行第三步,这一步要求我们创建一个删除任务的按钮。我觉得很可笑,因为我知道我可以解决这个问题,但是... a a.嗯,我还没有!我将发布代码,看看是否有任何初始问题。然后用我已经尝试过的方法更新。任何帮助都是非常感谢的。谢谢!

import React, { useState } from "react";
import "./App.css";

const App = () => {
  const [todos, setTodos] = useState([]);
  const [todo, setTodo] = useState("");

  const handleSubmit = (e) => {
      e.preventDefault();

      const newTodo = {
          id: new Date().getTime(),
          text: todo.trim(),
          completed: false,
      };

      if (newTodo.text.length > 0) {

          setTodos([...todos].concat(newTodo));
          setTodo("");

      } else {

          alert("Enter Valid Task");
          setTodo("");
      }
  }

  const deleteTodo = (id) => {
      let updatedTodos = [...todos].filter((todo) => todo.id !== id);
      setTodos(updatedTodos);
  }

  const button = <button onClick={() => deleteTodo(todo.id)}>Delete</button>

return (
    <div>
        <h1>To-do List</h1>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    onChange={(e) => setTodo(e.target.value)}
                    placeholder="Add a new task"
                    value={todo}
                />
                <button type="submit">Add Todo</button>
            </form>
            {todos.map((todo) => <div>ID: {todo.id} Task: {todo.text} {button}</div>)}
    </div>
    );
};

export default App;

我不只是复制和粘贴,所以有可能我在输入时搞砸了一些东西。我希望deleteTodo()函数接受一个todo.id,并过滤待办事项列表,排除我想删除的。我想这个问题可能是由我创建按钮的方式引起的?同样,我不知道为什么我不能弄清楚。TIA。
编辑:好的,现在可以了!非常感谢你们所有人的解释。对于其他遇到这个问题的人,这里是我的失误之处:

const button = <button onClick={() => deleteTodo(todo.id)}Delete<button>

@Nicholas Tower的解释非常清楚--在.map(...)之外创建这个函数会导致deleteTodo获取todo state,而不是我希望它从todos数组中删除的not todo。@Lars Vonk、@0stone0和@Sudip Shrestha都说过这一点。@Sudip Shrestha和@pilchard还帮助更正了deleteTodo函数。同样,我真的很感谢所有的帮助。代码现在工作。我将显示更新,以便人们有类似的问题可以比较:

import React from "react";
import "./App.css";

const App = () => {
  const [todos, setTodos] = React.useState([]);
  const [todo, setTodo] = React.useState("");

  const handleSubmit = (e) => {
      e.preventDefault();

      const newTodo = {
          id: new Date().getTime(),
          text: todo.trim(),
          completed: false,
      };

      if (newTodo.text.length > 0) {

          setTodos(todos.concat(newTodo));
          setTodo("");

      } else {

        alert("Enter a valid task");
        setTodo("");
      }
  }

  // update the state using setState, rathar than mutating it directly @Sudip Shrestha
  const deleteTodo = id => {
      setTodos(prevState => {
          return prevState.filter(todo => todo.id !== id)
      });
  };

// line 51: button placed inside .map(), as per many suggestions below.
return (
    <>
        <h1>Todo List</h1>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    onChange={(e) => setTodo(e.target.value)}
                    placeholder="Add a new task..."
                    value={todo}
                />
            </form>
            {todos.map((todo) => 
                <div>
                    ID: {todo.id} Task: {todo.text}
                    <button onClick={() => deleteTodo(todo.id)}>Delete</button>
                </div>)}
    </>
    );
};

export default App;
ee7vknir

ee7vknir1#

const button = <button onClick={() => deleteTodo(todo.id)}>Delete</button>

这个button元素只创建了一次,它引用的todo变量是todo状态,它是一个字符串(通常是空字符串),因为todo是字符串,todo.id就是undefineddeleteTodo不能对它做任何事情。
您需要为每个项目创建单独的按钮,因此应该将以下代码向下移动到.map中:

{todos.map((todo) => (
  <div>
    ID: {todo.id} Task: {todo.text}
    <button onClick={() => deleteTodo(todo.id)}>Delete</button>
  </div>
))}

现在每个元素都有了自己的按钮和onClick函数,在这些函数中,todo是数组中的元素。

tjrkku2a

tjrkku2a2#

按钮无法访问它具有的todo,我认为您应该将代码从const button放到您引用它的位置,或者将其更改为const button = (todo) => <button onClick={ () => deleteTodo(todo.id); }>Delete</button>,然后通过执行{button()}访问它

kse8i1jr

kse8i1jr3#

const button = <button onClick={() => deleteTodo(todo.id)}>Delete</button>

它对每个todo都有相同的回调,你应该把它移到你的map里面,这样todo.id就可以引用map()的迭代器:

{todos.map((todo) => (
    <React.Fragment>
        <div>ID: {todo.id} Task: {todo.text}</div>
        <button onClick={() => deleteTodo(todo.id)}>Delete</button>
    </React.Fragment>
))}

更新的演示:
一个二个一个一个

ovfsdjhp

ovfsdjhp4#

试试这个:

const button = (t) => <button onClick={() => deleteTodo(t.id)}>Delete</button>

然后在Map上

{todos.map((todo) => <div>ID: {todo.id} Task: {todo.text} {button(todo)}</div>)}

这样,"删除待办事项"按钮将绑定到特定的待办事项ID,避免绑定到应用程序中todo的当前值。

nqwrtyyt

nqwrtyyt5#

1.最好使用***setState***更新状态。直接禁用状态会破坏React数据流的主要原则(单向),使您的应用非常脆弱,基本上忽略了整个组件生命周期。
1.另外,您需要将***delete***从字符串更改为函数,并传递id或将jsx直接放置在map函数中。

import React, { useState } from 'react'

const App = () => {
  const [todos, setTodos] = useState([])
  const [todo, setTodo] = useState('')

  const handleSubmit = e => {
    e.preventDefault()

    const newTodo = {
      id: new Date().getTime(),
      text: todo.trim(),
      completed: false,
    }

    if (newTodo.text.length > 0) {
      setTodos([...todos].concat(newTodo))
      setTodo('')
    } else {
      alert('Enter Valid Task')
      setTodo('')
    }
  }

   /*
   * Changed Here
   */
  const deleteTodo = id => {
  
    setTodos(prevState => {
      return prevState.filter(todo => todo?.id != id)
    })
  }

  const button = id => <button onClick={() => 
  deleteTodo(id)}>Delete</button>

  return (
    <div>
      <h1>To-do List</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          onChange={e => setTodo(e.target.value)}
          placeholder="Add a new task"
          value={todo}
        />
        <button type="submit">Add Todo</button>
      </form>
      {todos.map(todo => (
        <div key={todo.id}>
          ID: {todo.id} Task: {todo.text} {button(todo.id)}
        </div>
      ))}
    </div>
  )
}

export default App
ma8fv8wu

ma8fv8wu6#

问题出现在:

const button = <button onClick={() => deleteTodo(todo.id)}>Delete</button>

您可以使用

const Button = (props) => {
  return (
    <button
      className={`btn ${props.className}`}
      title={`${props.title}`}
      onClick={props.onClick ? () => props.onClick() : null}
    >
      {props.children}
    </button>
  );
};

之后就这样叫吧

<Button className="delete" title="delete" onClick={()=>deleteTodo(todo.id)}>Delete</Button>

相关问题