列表项未正确删除(反应) [英] list items are not deleting properly (React)

查看:56
本文介绍了列表项未正确删除(反应)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

希望我的笔记应用程序能为您提供一些帮助.假设我的笔记列表上有3个笔记.我想删除列表顶部的注释.无论我尝试删除哪一个,始终会首先删除列表最底部的任何注释.我检查了React控制台,并且处于应用程序组件状态的notes数组表示已正确删除.但是从实际的角度来看,事实并非如此.如何获取它,以便删除我选择的确切音符?

I'd appreciate some help with my note taking app. Let's say I have 3 notes on my notes list. I want to delete the note at the top of the list. No matter which one I try to delete, it's always whichever note is at the very bottom of the list is deleted first. I checked the React console, and the notes array in the App Component's state says it's deleted properly. But in the actual view itself, it's not. How can I get it so that I delete the exact note that I chose?

    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属性来跟踪列表中的元素.当您从数组中间删除元素时,索引不会删除自身,而是会重新排列,最后一个索引会消失.这就是为什么数组中的最后一个元素总是被删除的原因.

This error is occurring from using index as your key. React uses the key attribute to track the elements inside the list. When you are deleting an element from the middle in an array, the index does not delete itself, instead it rearranges and the last index disappears. This is why the last element in your array always got deleted.

对于此解决方案,我将注释的title提供为key,但这可能并不总是唯一的.最好将生成的密钥或字段组合用作密钥

For this solution, I have provided title of the note as the key, but this may not be always unique. You will be better using a generated key or a combination of fields as key

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>

这篇关于列表项未正确删除(反应)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆