简体   繁体   English

从数组React中删除项目?

[英]Remove items from an array React?

I am making a form that allows a user to build a quiz (here's my code so far) 我正在制作一个允许用户构建测验的表单(这是我目前为止的代码)

var uuid = require("uuid-v4");
// Generate a new UUID
var myUUID = uuid();
// Validate a UUID as proper V4 format
uuid.isUUID(myUUID); // true

var questionNum = 0;

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      key: uuid(),
      title: "",
      author: "",
      questions: [],
      answers: []
    };

    this.handleChange = this.handleChange.bind(this);
    this.addQuestion = this.addQuestion.bind(this);
  }

  componentDidMount() {
    // componentDidMount() is a React lifecycle method
    this.addQuestion();
  }

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  /**
   * It's probably better to structure your questions like this:
   * this.state.questions: [{
   *         question: 'How are you?',
   *         answers: ['Good', 'Great', 'Awful'],
   *         // correctAnswer: 'Great'
   *     },
   *     {
   *         question: 'What is your name?',
   *         answers: ['Toby', 'Marco', 'Jeff'],
   *         // correctAnswer: 'Jeff'
   *     }];
   *
   * This allows you to keep better track of what questions
   * have what answers. If you're making a 'quiz' type structure,
   * you could additionally add a `correctAnswer` property.
   */

  addQuestion() {
    questionNum++;
    this.setState(previousState => {
      const questions = [...previousState.questions, "question", "hi"];
      const answers = [...previousState.answers];

      for (var i = 0; i < 4; i++) {
        answers.push({
          answerChoice: "",
          key: uuid()
        });
      }
      return { questions, answers };
    });
    console.log(
      this.state.answers,
      this.state.questions,
      questionNum,
      this.state.title,
      this.state.author
    );
  }

  render() {
    return (
      <div className="App">
        <div>
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <h1 className="App-title">Quiz Form 2.0</h1>
          </header>
          <p className="App-intro">
            To get started, edit <code>src/App.js</code> and save to reload.
          </p>
        </div>

        <div>
          <form>
            <div className="Intro">
              Give your Quiz a title:{" "}
              <input
                type="text"
                value={this.state.title}
                onChange={this.handleChange}
                name="title"
              />
              <br />
              Who's the Author?{" "}
              <input
                type="text"
                value={this.state.author}
                onChange={this.handleChange}
                name="author"
              />
              <br />
              <br />
            </div>
            <div className="questions">
              Now let's add some questions... <br />
              {// This is where we loop through our questions to
              // add them to the DOM.
              this.state.questions.map(question => {
                return <div>{question}</div>;
              })

              // This is what it would look like for the structure
              // I proposed earlier.
              // this.state.questions.map((question) {
              //   return (
              //       <div>{question.quesion}</div>
              //       {
              //           question.answers.map((answer) => {
              //               return (<div>{answer}</div>);
              //           })
              //       }
              //   );
              // })
              // This would output all questions and answers.
              }
            </div>
          </form>
          <button onClick={this.addQuestion}>Add Question</button>
        </div>
      </div>
    );
  }
}

export default App;

And I have come to the point where I want to try and be able to "Remove" a question (using a button). 我已经到了想要尝试并能够“删除”一个问题(使用按钮)的地步。 What my code does now is it adds objects to an array, and I have got that figured out. 我的代码现在做的是它将对象添加到数组中,并且我已经弄明白了。 But now I am trying to remove Items from the array. 但现在我正在尝试从数组中删除Items。 I was thinking "ok just remove the last question" but realistically users will want to remove any of their questions. 我在想“好的只是删除最后一个问题”,但实际上用户会想要删除他们的任何问题。 I was just curious if anyone had some tips for this, I really don't know how to start. 我只是好奇,如果有人有这方面的一些提示,我真的不知道如何开始。

If you want the user to be able to remove any question, add an onClick to the question div (or a child of the div - remember to move the onClick ). 如果您希望用户能够删除任何问题,请将onClick添加到问题div (或div的子项 - 记得移动onClick )。 The callback for that can accept an index, which refers to the element in the list to remove. 该回调可以接受索引,该索引引用要删除的列表中的元素。

Example: 例:

class App extends Component {
  constructor(props) {
    super(props)

    this.removeItem = this.removeItem.bind(this)
  }

  removeItem (index) {
    this.setState(({ questions }) => {
      const mQuestions = [ ...questions ]
      mQuestions.splice(index, 1)
      return { questions: mQuestions }
    })
  }

  render () {
    return (
      <div>
        ...
        { this.state.questions.map((question, index) => {
          return <div onClick={ () => this.removeItem(index) }>{ question }</div>
        }) }
      </div>
    )
  }
}

This isn't so much a react question as a JavaScript question. 这不是一个JavaScript问题的反应问题。 Since your questions are stored in your react state it will update the DOM when that state is modified. 由于您的问题存储在您的反应状态,因此在修改该状态时将更新DOM。 Simply removing the value from the array using this.setState() will suffice. 只需使用this.setState()从数组中删除值就足够了。

You have a few options for removing values from your array. 您有几个选项可以从数组中删除值。 The main thing to keep in mind here is to make sure you don't modify the actual array but rather replace it with a new instance of an array. 这里要记住的主要事项是确保不修改实际的数组,而是用一个新的数组实例替换它。 Modifying the array directly will not trigger updates and goes against the general principles of react state. 直接修改数组不会触发更新,违反反应状态的一般原则。 For example, using Array.prototype.splice() would modify your original array. 例如,使用Array.prototype.splice()会修改原始数组。 ( Array.prototype.splice docs ) Array.prototype.splice docs

In JavaScript, primatives such as strings and numbers are passed by value however objects such as arrays, sets, or generic JavaScript objects are passed by reference. 在JavaScript中,诸如字符串和数字之类的原型通过值传递,但是诸如数组,集合或通用JavaScript对象之类的对象通过引用传递。 This means that by assigning an object to a new variable you will now have two variables pointing at the same object. 这意味着通过将对象分配给新变量,您现在将有两个指向同一对象的变量。

const foo = [1];
const bar = foo;
console.log(foo); // [1]
console.log(bar); // [1]
foo.push(2);
console.log(foo); // [1, 2]
console.log(bar); // [1, 2]

One common way to get around this is by using the ES6 spread notation ( Spread operator docs ) to spread the values into a new array. 解决此问题的一种常见方法是使用ES6扩展符号( Spread运算符docs )将值扩展到新数组中。 const bar = [...foo] would return a copied array pointing to a separate object. const bar = [...foo]将返回指向单独对象的复制数组。 Applying this to your question, you could do const q = [...this.state.questions] and then modify q using q.splice(index, 1) and assign that to your state using this.setState() . 将其应用到你的问题,你可以做const q = [...this.state.questions]然后用修改q q.splice(index, 1)并分配使用,为您的状态this.setState() There are obviously other options to removing items from an array and I suppose it is not a given that you know the index of the array. 显然有其他选项可以从数组中删除项目,我认为不知道数组的索引。 In this case, tools such as Array.prototype.find() or Array.prototype.findIndex() are helpful or you could use a JavaScript Map object ( Map docs ) in place of your array to eliminate the need for indexes while maintaining question order. 在这种情况下, Array.prototype.find()Array.prototype.findIndex()等工具Array.prototype.find()用,或者您可以使用JavaScript Map对象( Map docs )代替您的数组,以在保持问题的同时消除对索引的需求订购。 All of these options are equally valid so I'll leave it to you to determine how you want to go about it. 所有这些选项都同样有效,所以我会留给您确定您想要的方式。

In order to actually trigger the deletion you will need to have some sort of user control on the page. 为了实际触发删除,您需要在页面上进行某种用户控制。 You can do this with click listeners on elements, specific buttons included in the HTML for each question, or maybe even a dropdown menu elsewhere for deletion. 您可以使用元素上的单击侦听器,每个问题的HTML中包含的特定按钮,甚至可以删除其他位置的下拉菜单来执行此操作。 The end result will be that the element the user interacts with will maintain a unique ID so that when it activates the callback function you can determine which question it is that should be deleted. 最终结果是用户与之交互的元素将保持唯一的ID,以便在激活回调函数时,您可以确定应该删除哪个问题。 This ID will be stored in the first argument of your function. 此ID将存储在函数的第一个参数中。 In most examples this will be named "event". 在大多数示例中,这将被命名为“事件”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM