从React数组中删除项?

4

我正在制作一个表单,允许用户构建测验(这是目前我的代码)

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;

我现在想尝试通过一个按钮来“删除”问题。目前我的代码只是将对象添加到数组中,这个部分我已经弄清楚了。但现在我要从数组中删除项目,我曾想过“好的,只需删除最后一个问题”,但实际上用户可能想删除他们的任何问题。我很好奇是否有人有一些提示,因为我真的不知道该从哪里开始。

2个回答

12
如果您希望用户能够删除任何问题,请在问题
(或其子元素 - 记得移动onClick)中添加一个onClick。回调可以接受一个索引,该索引指向要删除的列表中的元素。

示例:

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>
    )
  }
}

slice takes a beginning and end args, not start/count - Tyler Sebastian
你仍在改变状态,这就是我使用扩展语法来创建副本的原因。 - Tyler Sebastian
“你不同意吗?” “是的,我同意。” 再次强调,在this.setState回调函数内部进行本地突变,但不要返回原始的、突变的状态——使用[...questions]创建一个副本。 - Tyler Sebastian
1
+1,这个可以。我习惯于使用像immutablejs这样的好用的不可变库 - 这个原生JS实在是太累人了 :P - Tyler Sebastian

1
这不是一个React问题,而是一个JavaScript问题。由于您的问题存储在React状态中,当该状态被修改时,它将更新DOM。只需使用this.setState()从数组中删除值即可。
您有几个选项可以从数组中删除值。在此要记住的主要事项是确保您不修改实际数组,而是用新的数组实例替换它。直接修改数组不会触发更新,并违反了React状态的一般原则。例如,使用Array.prototype.splice()将修改您的原始数组。 (Array.prototype.splice文档)
在JavaScript中,诸如字符串和数字之类的基元通过值传递,但是数组、集合或通用JavaScript对象等对象通过引用传递。这意味着通过将对象分配给新变量,您现在将拥有两个指向同一对象的变量。
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]

一种常见的解决方法是使用 ES6 扩展符(Spread operator docs)将值扩展到一个新数组中。 const bar = [...foo] 将返回一个指向单独对象的复制数组。将其应用于您的问题,您可以使用 const q = [...this.state.questions],然后使用 q.splice(index, 1) 修改 q,并使用 this.setState() 将其分配给您的状态。显然,还有其他从数组中删除项的选项,我想你可能不知道数组的索引。在这种情况下,像 Array.prototype.find()Array.prototype.findIndex() 这样的工具很有帮助,或者您可以使用 JavaScript Map 对象(Map docs)代替数组,以消除索引的需要,同时保持问题的顺序。所有这些选项都是同样有效的,所以我会让您确定如何处理它。
为了实际触发删除,您需要在页面上拥有某种用户控件。您可以使用元素上的单击侦听器、包含在每个问题的HTML中的特定按钮,或者甚至是其他地方的下拉菜单来实现此操作。最终结果将是,用户交互的元素将保持唯一的ID,以便当它激活回调函数时,您可以确定应该删除哪个问题。此ID将存储在您的函数的第一个参数中。在大多数示例中,这将被命名为“事件”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接