我正在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()
答案 0 :(得分:2)
您的delete
操作在数组中留下一个空对象,当您循环访问它时,它无法获取其id
属性。通常,可以通过多种方式改进代码:
delete
是行不通的。在删除操作中使用过滤器:this.setState({this.state.todos.filter(todo => todo.id !== id)})
答案 1 :(得分:2)
delete
运算符导致错误使用delete运算符删除数组元素时,数组长度不会受到影响。
这意味着如果数组有三个待办事项[{todo}, {todo}, {todo}]
删除第二个元素时:delete todos[1]
待办事项将更改为:[{todo}, empty, {todo}]
如您所见,数组的长度仍然是三,所以错误发生在for语句中。
map
起作用:仅对具有已分配值(包括未定义)的数组索引进行调用。不会因为缺少数组元素(即从未设置,已删除或从未分配值的索引)而调用它。
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运算符引起的长度错误的问题。