我通过制作一个简单的待办事项清单来学习React。到目前为止爱它。
当我删除待办事项时,它会删除单击要删除的列表项以上。我的索引必须关闭,但我无法找到原因。
没有奇怪的CSS去除每个项目的渲染删除按钮。索引似乎只是针对它上面的项目。
代码(缩短)
handleSubmit(event) {
let newTodos = this.state.todos;
let index = newTodos.length;
if (this.state.input !== "") {
newTodos.unshift({
text: this.state.input,
key: this.state.input
});
}
this.setState({todos: newTodos, input: ""});
event.preventDefault();
this.setLocalStorage();
}
deleteItem(index) {
let todoItems = this.state.todos;
todoItems.splice(index, 1);
this.setState({
todos: todoItems
});
this.setLocalStorage();
}
render() {
return (
<div className="todo-holder">
<form className="todoInput-holder" onSubmit={this.handleSubmit}>
<input type="text" placeholder="To do..." value={this.state.input} onChange={this.handleChange} />
</form>
<ul id="todo-list">
<FlipMove duration={250} easing="ease-out">
{
this.state.todos.map(todos => {
return <li key={todos.key} className="todo-li-item" >
<span className="todo-item">{todos.text}</span>
<span onClick={this.deleteItem} className="delet-todo">✕</span>
</li>;
})
}
</FlipMove>
</ul>
</div>
);
}
思想?
答案 0 :(得分:2)
原因实际上非常简单:onClick
期望您传入参数为event
的函数(请参阅ReactJS documentation)。因此,index
deleteItem(index)
event
所期望的位置放置了splice
个对象。 JavaScript在event
调用中进行了秘密类型转换,因为event => event is an object => convert to valid Number is impossible => event becomes NaN => todos.splice(NaN, 1) => somehow splice treats NaN as 0 always
不是数字,这导致您遇到的奇怪行为。
deleteItem
要解决此问题,您可以更改(index, event)
以event
作为2个参数(实际上,如果您不打算使用bind
,可以忽略它),并且您可以index
MDN doc)todos.map(el, index => { ... })
(通过todos
检索)从event
到它,以绕过默认的class App extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
todos: []
}
}
handleSubmit = (event) => {
let newTodos = this.state.todos;
let index = newTodos.length;
if (this.state.input !== "") {
newTodos.unshift({
text: this.state.input,
key: this.state.input
});
}
this.setState({todos: newTodos, input: ""});
event.preventDefault();
}
deleteItem = (index, e) => {
let todoItems = this.state.todos;
todoItems.splice(index, 1);
this.setState({
todos: todoItems // other answers complains about deep copy, but it is not the core issue here
});
}
handleChange = (e) => {
this.setState({
input: e.target.value
})
}
render() {
return (
<div className="todo-holder">
<form className="todoInput-holder" onSubmit={this.handleSubmit}>
<input type="text" placeholder="To do..." value={this.state.input} onChange={this.handleChange} />
<button type="submit">submit</button>
</form>
<ul id="todo-list">
{
this.state.todos.map((todos, i) => { // i is the index of current todo entry
return <li key={todos.key} className="todo-li-item" >
<span className="todo-item">{todos.text}</span>
<span onClick={this.deleteItem.bind(this, i) /* this binds `i` to the first parameter of deleteItem(i, event) */} className="delet-todo">✕</span>
</li>;
})
}
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'))
参数。< / p>
以下代码是可运行的,我删除了localStorage代码以使其正常工作,如果需要,可以将其添加回来。
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
float
答案 1 :(得分:1)
您实际上并未将索引传递给deleteItem
方法。
首先,将索引传递给方法:
this.state.todos.map((todos, index) => {
return <li key={todos.key} className="todo-li-item" >
<span className="todo-item">{todos.text}</span>
<span onClick={() => this.deleteItem(index)} className="delet-todo">✕</span>
</li>;
})
其次,不要使用splice等方法改变React的状态。 React状态中的任何内容都应该是不可变的,并且只能用setState触及。如果您要使用splice,请确保在数组的副本上执行此操作,例如
deleteItem(index) {
// .slice() will make a copy of the array
let todoItems = this.state.todos.slice();
todoItems.splice(index, 1);
this.setState({
todos: todoItems
});
this.setLocalStorage();
}
然而,更清晰的解决方案是使用Array的filter
方法:
deleteItem(index) {
let todoItems = this.state.todos.filter((_, i) => i !== index)
this.setState({
todos: todoItems
});
this.setLocalStorage();
}
或者,在React中使用您用于key
的任何属性:
this.state.todos.map((todos) => {
return <li key={todos.key} className="todo-li-item" >
<span className="todo-item">{todos.text}</span>
<span onClick={() => this.deleteItem(todos.key)} className="delet-todo">✕</span>
</li>;
})
deleteItem(key) {
let todoItems = this.state.todos.filter((todo) => todo.key !== key)
this.setState({
todos: todoItems
});
this.setLocalStorage();
}
答案 2 :(得分:0)
这里有两个问题:
<span onClick={() => this.deleteItem(index)} className="delet-todo">✕</span>
所以,基本上你需要改变你调用函数的方式到这样的
public class Adapter1 extends BaseAdapter {
private Context mContext;
// Keep all Images in array
public Integer[] mThumbIds = {
R.drawable.img1,
R.drawable.img2,
R.drawable.img3,
R.drawable.img4,
R.drawable.img5,
R.drawable.img6,
R.drawable.img7,
R.drawable.img8,
R.drawable.img9,
R.drawable.img10,
R.drawable.img11,
R.drawable.img12,
R.drawable.img13
};
希望它有所帮助!
答案 3 :(得分:0)
在render()方法中,不将索引传递给项目对象
this.state.todos.map((todos, index) =>
<li key={todos.key} className="todo-li-item" >
<span className="todo-item">{todos.text}</span>
<span onClick={() => this.deleteItem(index)} className="delet-todo">✕</span>
</li>
);