在React-map vs for循环中删除集合项



我正在React中创建一个简单的待办事项应用程序。最后,我在修修补补,想用各种方法取得同样的结果。

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

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.slice()代替const todos = this.state.todos

delete运算符导致错误

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

删除数组元素

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

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

todo将更改为:[{todo}, empty, {todo}]

正如您所看到的,数组的长度仍然是三,因此错误发生在for语句中。

map工作原理:

映射回调仅针对已分配值(包括未定义值(的数组索引调用。它不会为数组中缺少的元素(即从未设置、已删除或从未分配值的索引(调用。

地图描述

PS:当你检查错误时,你可以添加一些日志来检查发生的时间。:D

delete操作在数组中留下一个空对象,当循环到达它时,它无法获得其id属性。一般来说,代码可以通过多种方式进行改进:

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

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

for(var i=0; i<todos.length; i++) {
if (todos[i].id === id) {
todos.splice(i, 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);

不可变数据是react应用程序的推荐方式。不要删除数组中的元素。创建一个没有所需元素的新元素。最快的方法是将元素推送到一个新的数组中。

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运算符导致长度错误的问题。

最新更新