javascript - 在 React 中推送到数组,意外行为
问题描述
尝试制作待办事项列表应用程序
我希望我的待办事项具有唯一的键/ID。我想通过获取最后一个待办事项并将 1 添加到其 id 来创建待办事项 id。如果该项目不存在,它会创建一个 id = 1 的新项目。
应用程序.js:
import React, {Component} from 'react';
import Todos from './Todos'
import AddTodo from './AddForm'
class App extends Component {
state = {
todos: [
{id: 1, content: 'buy milk'},
{id: 2, content: 'play nintendo'}
]
}
addTodo = (todo) => {
if (this.state.todos[0])
{
todo.id = this.state.todos[this.state.todos.length-1].id +1;
let todos = [...this.state.todos];
todos.push(todo);
this.setState({
todos: todos
});
}
else
{
this.setState({
todos: [
{id: 1, content: todo.content}
]
});
}
console.log(this.state.todos);
}
render() {
return(
<div className="todo-app container">
<h1 className="center blue-text">Todos:</h1>
<Todos deleteTodo={this.deleteTodo} todos={this.state.todos}/>
<AddTodo addTodo={this.addTodo} />
</div>
);
}
}
这几乎可以工作。如果项目具有独特的内容,我可以添加新项目,但是当项目具有相同的内容时会出现问题。
独特的内容console.log:
0: {content: "buy milk", id: 1}
1: {content: "play nintendo", id: 2}
2: {content: "adrfhahhafafdhafhafhhfa", id: 3}
3: {content: "adrfhahhafafdhafhafhhfaafhafhfah", id: 4}
4: {content: "adrfhahhafafdhafhafhhfaafhafhfahafhfahafh", id: 5}
5: {content: "adrfhahhafafdhafhafhhfaafhafhfahafhfahafhafhafhfah", id: 6}
相同的内容console.log:
0: {content: "buy milk", id: 1}
1: {content: "play nintendo", id: 2}
2: {content: "adrfhahhafafdhafhafhhfa", id: 3}
3: {content: "adrfhahhafafdhafhafhhfaafhafhfah", id: 4}
4: {content: "adrfhahhafafdhafhafhhfaafhafhfahafhfahafh", id: 5}
5: {content: "adrfhahhafafdhafhafhhfaafhafhfahafhfahafhafhafhfah", id: 7}
6: {content: "adrfhahhafafdhafhafhhfaafhafhfahafhfahafhafhafhfah", id: 7}
如您所见,如果内容相同,则 id 相同。
我知道这可能是在反应中添加 id:s 的错误方法,但我想了解发生了什么。提前致谢。
编辑:如果项目被删除,Yevgen 指出我的逻辑存在缺陷,但我仍然不明白为什么ID:s 重复。有人要求提供其余代码,所以我将其全部添加。
AddForm.js
import React, {Component} from 'react';
class AddTodo extends Component {
state = {
content: ''
}
handleChange = (e) => {
this.setState({
content: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
this.props.addTodo(this.state);
}
render(){
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>Add new todo</label>
<input type="text" onChange={this.handleChange} />
</form>
</div>
);
}
}
export default AddTodo;
Todos.js
import React from 'react'
const Todos = ({todos, deleteTodo}) => {
const todoList = todos.length ? (
todos.map(todo => {
return (
<div className="collection-item" key={todo.id}>
<span onClick={() => {deleteTodo(todo.id)}}>{todo.content}</span>
</div>
)
})
) : (
<p className="center">You have no todos left</p>
)
return (
<div className="todos collection">
{todoList}
</div>
)
}
export default Todos;
解决方案
我的猜测是您的问题来自您声明<AddForm />
组件状态的方式。您应该在 constrictor 体内完成此操作,如this.state
. 您当前所做的是全局变量声明。因此,它不受您的应用程序状态的约束,并且您id
的分配不正确。
除此之外,您的addTodo()
外观过于复杂且容易出错(您不能依靠数组长度来获得最大使用id
量,因为删除项目,而不是最后一个会破坏逻辑)。
此外,通常建议避免在类方法中使用箭头符号。相反,您应该将它们声明为常规函数并做一些事情,例如this.addTodo = this.addTodo.bind(this)
在您声明的每个方法的构造函数主体中。否则,如果您非常喜欢箭头函数,那么您可能会更喜欢函数组件。
按照您的逻辑分配 autoincremented id
(因此,id
已删除项目的 's 永远不会被重用)并将具有属性的对象传递content
给addTodo()
,您可以简单地完成:
addTodo({content}){
const id = Math.max(...this.state.todos.map(({id}) => id),0)+1
this.setState({todos:[...this.state.todos, {id, content}]})
}
推荐阅读
- c# - 使用 CorrelationId 上下文更新 Dynamics 365 中的实体
- spring-boot - Spring boot - 健康端点 - 我可以有多个 URI,一个简单,另一个更详细?
- windows - 将 Git Bash 中命令的输出通过管道传输到 Windows 上的 Powershell 脚本
- python - 如何仅使用 numpy 操作根据其他两个 numpy 数组的条件获取新的 numpy 数组?
- javascript - Telegraf:等待用户回复并立即使用
- reactjs - 有ngrok的替代品吗?
- reactjs - React-Leaflet / OpenStreetMap:检测标记是否在圆圈内
- python - 如何在python中创建网格边框?
- sql - 如何查找模式中所有视图的行数?
- python - SVM 训练根据训练数据集的配置无休止地运行