在React中删除集合项-映射与for循环

时间:2018-12-05 14:14:35

标签: javascript reactjs

我正在React中创建简单的待办应用。 最后,我正在修补,并希望通过各种方式获得相同的结果。

当我在map中用render方法填充数组时,一切都很好:

const todosItems = this.state.todos.map((todo) =>
  <TodoItem name={todo.text} key={todo.id} onClick={(e) => this.deleteButtonClick(todo.id)} />
);

当我通过for循环执行相同的操作时:

const todosItems = [];
const todos = this.state.todos;
for (let i = 0; i < todos.length; i++) {
  todosItems.push(<TodoItem name={todos[i].text} key={todos[i].id} onClick={(e) => this.deleteButtonClick(todos[i].id)} />);
}

当我删除以下项目之一时,应用程序崩溃:

[Error] TypeError: undefined is not an object (evaluating 'todos[i].text')
_loop (index.js:17650)
render (index.js:17659)
finishClassComponent (index.js:5285:149)
performUnitOfWork (index.js:5931:360)
workLoop (index.js:5938)
callCallback (index.js:2613:108)
dispatchEvent
invokeGuardedCallbackDev (index.js:2633)
invokeGuardedCallback (index.js:2649:791)
replayUnitOfWork (index.js:5800:88)
renderRoot (index.js:5960:160)
performWorkOnRoot (index.js:6151)
performWork (index.js:6133:813)
performSyncWork (index.js:6131:155)
interactiveUpdates$1 (index.js:6184:488)
dispatchInteractiveEvent (index.js:3758:115)
dispatchInteractiveEvent

完整代码:https://github.com/ArturKot95/todo-react/blob/master/index.js

预先感谢您的帮助。

编辑: 谢谢您的解决方案:D。对我来说最重要的是在学习React时认为状态就像程序中的快照一样,一定不能直接影响组件的状态,而是可以处理副本。

delete替换为Array.prototype.filter

deleteButtonClick = (id) => {
    let todos = this.state.todos.slice();
    todos = todos.filter(todo => todo.id !== id);

    this.setState({
        todos: todos
    });
}

const todos = this.state.todos替换为const todos = this.state.todos.slice()

5 个答案:

答案 0 :(得分:2)

您的delete操作在数组中留下一个空对象,当您循环访问它时,它无法获取其id属性。通常,可以通过多种方式改进代码:

    数组上的
  1. delete是行不通的。在删除操作中使用过滤器:this.setState({this.state.todos.filter(todo => todo.id !== id)})
  2. 不鼓励使用push,只需映射/过滤数组即可。

答案 1 :(得分:2)

delete运算符导致错误

  

使用delete运算符删除数组元素时,数组长度不会受到影响。

deleting array elements

这意味着如果数组有三个待办事项[{todo}, {todo}, {todo}]

删除第二个元素时:delete todos[1]

待办事项将更改为:[{todo}, empty, {todo}]

如您所见,数组的长度仍然是三,所以错误发生在for语句中。

为什么map起作用:

  

仅对具有已分配值(包括未定义)的数组索引进行调用。不会因为缺少数组元素(即从未设置,已删除或从未分配值的索引)而调用它。

map description

PS:检查错误时,可以添加一些日志以检查何时发生。 :D

答案 2 :(得分:1)

要解决此错误,您需要使用以下方法更改delete方法中的代码:

    for(var i=0; i<todos.length; i++) {
      if (todos[i].id === id) {
        todos.splice(i, 1)
      }
    }

答案 3 :(得分:1)

现在,您直接在此代码块中更改状态:

const todos = this.state.todos;
for (let todo in todos) {
  if (todos[todo].id === id) {
    delete todos[todo];
  }
}

这可能会在您的应用程序中引起各种问题。如Meir所述,您通常希望映射/过滤数组,但我想我也要注意,将todos状态的值分配给新对象,对其进行修改,然后使用此新对象设置状态即可您当前的设置方式。

const todos = Object.assign({}, this.state.todos);

答案 4 :(得分:1)

不可变数据是React应用的推荐方式。 不要删除数组的元素。创建一个不包含不需要元素的新元素。 fastest way是通过将元素推到新数组来实现的。

  deleteButtonClick = (id) => {
      const todos = this.state.todos;
      let res = [];
      for (let i = 0; i < todos.length; i++) {
        if (todos[i].id !== id) {
          res.push(todos[i]);
        }
      }
      this.setState({
        todos: res
      });
  }

由于它是一个新数组,因此不会有由delete运算符引起的长度错误的问题。