我希望我的笔记应用程序能为您提供一些帮助。假设我的记事清单上有3个记事。我想删除列表顶部的注释。无论我尝试删除哪一个,始终会首先删除列表最底部的注释。我检查了React控制台,并且处于应用程序组件状态的notes数组表示已正确删除。但实际上,事实并非如此。如何获得它以便删除我选择的确切音符?
class App extends Component { constructor(props) { super(props); this.state = { notes: [], title: "", details: "" } this.updateTitle = this.updateTitle.bind(this); this.updateDetails = this.updateDetails.bind(this); this.submitHandler = this.submitHandler.bind(this); this.deleteHandler = this.deleteHandler.bind(this); } updateTitle(event) { this.setState({ title: event.target.value }); } updateDetails(event) { this.setState({ details: event.target.value }); } submitHandler(e) { e.preventDefault(); if (!this.state.title.length || !this.state.details.length) { return; } const newNote = { newTitle: this.state.title, newDetails: this.state.details } this.setState(prevState => ({ notes: prevState.notes.concat(newNote), title: "", details: "" })) } deleteHandler(id) { this.setState(prevState => ({ notes: prevState.notes.filter((el)=> el !== id) })) } render() { return ( <div className="container"> <h1 className="title">React Notes App</h1> <NoteForm titleValue={this.state.title} detailsValue={this.state.details} titleHandle={this.updateTitle} detailsHandle={this.updateDetails} onSubmit={this.submitHandler} /> <div className="entry-section"> {this.state.notes.map((note,i) => ( <NoteEntry key={i} title={note.newTitle} details={note.newDetails} deleteNote={this.deleteHandler.bind(this,note)} /> ))} </div> </div> ); } } const NoteForm = (props) => { return ( <div> <form className="form-section"> <input className="title-input" type="type" placeholder="Title" value={props.titleValue} onChange={props.titleHandle} /> <br /> <textarea className="details-input" cols="20" rows="3" placeholder="Details" value={props.detailsValue} onChange={props.detailsHandle} /> <br /> <button className="input-button" onClick={props.onSubmit} >Add Note</button> </form> </div> ) } class NoteEntry extends Component { constructor(props) { super(props); this.state = { display: false, editing: false, editTitle: this.props.title, editDetails: this.props.details } this.displayToggle = this.displayToggle.bind(this); this.edit = this.edit.bind(this); this.save = this.save.bind(this); } displayToggle() { this.setState(prevState => ({ display: !prevState.display })) } edit() { this.setState({ editing: true }) } save() { let titleVal = this.refs.updateTitle.value; let detailsVal = this.refs.updateDetails.value; this.setState({ editTitle: titleVal, editDetails: detailsVal, editing: false }) } render() { return ( <div className="entry"> <div className="entry-header" onClick={this.state.editing ? null : this.displayToggle}> {this.state.editing ? ( <input ref="updateTitle" className="edit-title" type="text" defaultValue={this.state.editTitle} /> ) : ( <h2 className="entry-title">{this.state.editTitle}</h2> )} <p className="timestamp">{this.displayTime}</p> </div> <hr /> <div className={"entry-content " + (!this.state.display ? "hide-details" : null)}> {this.state.editing ? ( <textarea ref="updateDetails" className="edit-details" cols="10" rows="2" defaultValue={this.state.editDetails}></textarea> ) : ( <p className="details">{this.state.editDetails}</p> )} <div className="entry-buttons"> {this.state.editing ? ( <button className="save" onClick={this.save}>Save</button> ) : ( <button className="edit" onClick={this.edit}>Edit</button> ) } <button className="delete" onClick={this.props.deleteNote}>Delete</button> </div> </div> </div> ) } }
index用作时发生此错误key。React使用该key属性来跟踪列表中的元素。当您从数组中间删除元素时,索引不会删除自身,而是会重新排列,最后一个索引会消失。这就是为什么数组中的最后一个元素总是被删除的原因。
index
key
对于此解决方案,我提供title的注释为key,但这可能并不总是唯一的。使用生成的密钥或字段组合作为密钥会更好
title
class NoteEntry extends React.Component { constructor(props) { super(props); this.state = { display: false, editing: false, editTitle: this.props.title, editDetails: this.props.details } this.displayToggle = this.displayToggle.bind(this); this.edit = this.edit.bind(this); this.save = this.save.bind(this); } displayToggle() { this.setState(prevState => ({ display: !prevState.display })) } edit() { this.setState({ editing: true }) } save() { let titleVal = this.refs.updateTitle.value; let detailsVal = this.refs.updateDetails.value; this.setState({ editTitle: titleVal, editDetails: detailsVal, editing: false }) } render() { return ( <div className="entry"> <div className="entry-header" onClick={this.state.editing ? null : this.displayToggle}> {this.state.editing ? ( <input ref="updateTitle" className="edit-title" type="text" defaultValue={this.state.editTitle} /> ) : ( <h2 className="entry-title">{this.state.editTitle}</h2> )} <p className="timestamp">{this.displayTime}</p> </div> <hr /> <div className={"entry-content " + (!this.state.display ? "hide-details" : null)}> {this.state.editing ? ( <textarea ref="updateDetails" className="edit-details" cols="10" rows="2" defaultValue={this.state.editDetails}></textarea> ) : ( <p className="details">{this.state.editDetails}</p> )} <div className="entry-buttons"> {this.state.editing ? ( <button className="save" onClick={this.save}>Save</button> ) : ( <button className="edit" onClick={this.edit}>Edit</button> ) } <button className="delete" onClick={this.props.deleteNote}>Delete</button> </div> </div> </div> ) } } const NoteForm = (props) => { return ( <div> <form className="form-section"> <input className="title-input" type="type" placeholder="Title" value={props.titleValue} onChange={props.titleHandle} /> <br /> <textarea className="details-input" cols="20" rows="3" placeholder="Details" value={props.detailsValue} onChange={props.detailsHandle} /> <br /> <button className="input-button" onClick={props.onSubmit}> Add Note </button> </form> </div> ) } class App extends React.Component { constructor(props) { super(props); this.state = { notes: [], title: "", details: "" } this.updateTitle = this.updateTitle.bind(this); this.updateDetails = this.updateDetails.bind(this); this.submitHandler = this.submitHandler.bind(this); this.deleteHandler = this.deleteHandler.bind(this); } updateTitle(event) { this.setState({ title: event.target.value }); } updateDetails(event) { this.setState({ details: event.target.value }); } submitHandler(e) { e.preventDefault(); if (!this.state.title.length || !this.state.details.length) { return; } const newNote = { newTitle: this.state.title, newDetails: this.state.details } this.setState(prevState => ({ notes: prevState.notes.concat(newNote), title: "", details: "" })) } deleteHandler(id) { this.setState(prevState => ({ notes: prevState.notes.filter((el)=> el !== id) })) } render() { return ( <div className="container"> <h1 className="title">React Notes App</h1> <NoteForm titleValue={this.state.title} detailsValue={this.state.details} titleHandle={this.updateTitle} detailsHandle={this.updateDetails} onSubmit={this.submitHandler} /> <div className="entry-section"> {this.state.notes.map((note,i) => ( <NoteEntry key={note.newTitle} title={note.newTitle} details={note.newDetails} deleteNote={this.deleteHandler.bind(this,note)} /> ))} </div> </div> ); } } ReactDOM.render(<App />, document.getElementById('root')); <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="root"></div>