我对React很陌生,我正在尝试通过构建一个简单的notes应用程序进行练习。 Afaik /可以告诉您一切顺利,但是!我读到状态不应该手动更新,因此我正在复制状态数组并过滤出删除操作的结果。
但是失败了!
相反,如果我使用控制台日志,它将正确地从状态数组中删除要删除的元素,但是,当我在副本上调用setState()来更新视图时,该列表是错误的!
由于某种原因,我的React列表总是从页面上直观地删除最后一个元素,然后出现,然后与我的状态不同步。
该应用程序本身是带有嵌套列表和列表项组件的各种Form容器,它们使用来自表单类的道具进行管理。
有人可以帮我弄清楚我在做什么错吗?
谢谢!
表格类
class NotesForm extends Component {
constructor(props) {
super(props);
const list = [
{ text: "Build out UI" },
{ text: "Add new note" },
{ text: "delete notes" },
{ text: "edit notes" }
];
this.state = {
'notes': list
};
// this.notes = list;
this.handleSubmit = this.handleSubmit.bind(this);
this.deleteNote = this.deleteNote.bind(this);
}
handleSubmit(e) {
e.preventDefault();
if (this.input.value.length === 0) { return; }
this.state.notes.push({text: this.input.value});
this.setState({ notes: this.state.notes });
this.input.value = "";
}
// BUG - deletes WRONG note!!
deleteNote(note) {
console.log({'DELETE_NOTE': note.text})
// var list = _.clone(this.state.notes);
var list = [...this.state.notes];
var filteredNotes = _.filter(list, function(n) {
return (n.text !== note.text);
})
console.log({
'list': list,
'filteredNotes': filteredNotes
})
this.setState({ notes: filteredNotes });
}
render() {
return (
<div className="row notes-form">
<div className="col-xs-12">
<form onSubmit={this.handleSubmit}>
<input type="text" className="new-note-input" ref={(input) => this.input = input} />
<br />
<button className="add-btn btn btn-info btn-block" type="button" onClick={this.handleSubmit}>Add</button>
<br />
<NotesList notes={this.state.notes} deleteNote={this.deleteNote} />
</form>
</div>
</div>
);
}
}
清单类别
class NotesList extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ul className="notes-list">
{this.props.notes.map((n, index) => <NotesListItem key={index} note={n} deleteNote={this.props.deleteNote} />)}
</ul>
);
}
}
清单项目类别
class NotesListItem extends Component {
constructor(props) {
super(props);
this.state = {
'text': props.note.text
};
this.delete = this.delete.bind(this);
}
delete() {
this.props.deleteNote(this.props.note);
}
render() {
return (
<li className="notes-list-item">
<span className="item-text">{this.state.text}</span>
<div className="notes-btn-group btn-group" role="group">
<button className="delete-btn btn btn-danger" type="button" onClick={this.delete}>×</button>
</div>
</li>
);
}
}
最佳答案
对于index
中的每个key
,请尝试使用类似唯一ID的名称代替NotesListItem
作为NotesList
。参见以下相关的question(实际上可能是重复的):
import React, { Component } from 'react';
import NotesListItem from './NotesListItem';
class NotesList extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ul className="notes-list">
{this.props.notes.map((n, index) => <NotesListItem key={n.id} note={n} deleteNote={this.props.deleteNote} />)}
</ul>
);
}
}
export default NotesList;
您可以使用uuid之类的东西来生成“唯一” ID。生成唯一密钥的方法有很多,但这取决于您的数据结构。同样,使用唯一的id和基于id的筛选,可以帮助避免数组中的两个注释与基于
text
值的筛选具有相同文本的情况会同时删除它们。import uuidv1 from 'uuid/v1';
// ...
handleSubmit(e) {
e.preventDefault();
if (this.input.value.length === 0) { return; }
this.state.notes.push({id: uuidv1(), text: this.input.value});
this.setState({ notes: this.state.notes });
this.input.value = "";
}
我只建议使用这样的内容,因为您的文本可能会重复。您甚至可以使用以下方法摆脱困境:
{this.props.notes.map((n, index) => <NotesListItem key={index + n.text} note={n} deleteNote={this.props.deleteNote} />)}
另外,您不应该像
this.state.notes.push({text: this.input.value});
这样直接改变状态。尝试这样的事情:handleSubmit(e) {
e.preventDefault();
if (this.input.value.length === 0) { return; }
const note = { id: uuidv1(), text: this.input.value };
const notes = [...this.state.notes, note];
this.setState({ notes });
this.input.value = "";
}
另外,我避免使用
ref
处理受控输入,尤其是设置值。为什么不在状态上创建一个属性来与简单的onChange
事件处理程序结合使用来处理输入的值。这将与React Forms文档和处理输入值更新的“标准” React方法保持一致:handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (this.state.text.length === 0) { return; }
const note = { id: uuidv1(), text: this.state.text };
const notes = [...this.state.notes, note];
this.setState({ text: '', notes });
}
render() {
// ...
<input type="text" className="new-note-input" value={this.state.text} onChange={this.handleChange} />
// ...
}
这是一个正在起作用的example。
另一个答案可能足以解决您的问题。我建议回顾一下React article文档中提到/链接的以下Keys,其中讨论了将索引用作键的潜在负面影响。
希望有帮助!