【问题标题】:How can I dynamically delete components with React如何使用 React 动态删除组件
【发布时间】:2021-02-26 21:28:27
【问题描述】:

我很欣赏这个问题可能会保证回答太长,但我真的很难弄清楚如何使我的 React 应用程序正常工作。以下是我正在尝试做的事情以及我坚持的事情!

我正在创建一个测验平台,您可以在其中构建和玩由您和您的朋友制作的测验。您应该能够添加任意数量的问题,并且每个问题最多可以添加四个答案。下面是一张突出显示我目前正在开发的基本测验生成器的图片。

到目前为止,我能够创建尽可能多的问题,并且能够创建尽可能多的答案,但是我真的很难为问题和答案设置删除按钮,以便删除相应的问题或答案.

以下是我现有的代码。我有 3 个组件, , , .

测验生成器

import React from 'react';
import 'material-icons';
import '../css/addQuestion.css';
import AddTextQuestion from './addTextQuestion.js';

class QuizBuilder extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      noQuestions: 0,
    };
    this.addTextQuestion = this.addTextQuestion.bind(this);
  }

  addTextQuestion() {
    this.setState({
      noQuestions: this.state.noQuestions + 1,
    });
  }

  render() {
    let children = [];

    for(let i = 0; i < this.state.noQuestions; i++) {
      children.push(<AddTextQuestion key={i} qNo={i + 1}/>);
    }

    return (
      <div>
        <h2 className="builderHeader">Quiz Builder</h2>
        <div className="questionDiv" id="newQuestionContainer"></div>
        <form className="addQForm">
          {children}
        </form>
        <button type="button" id="addQuestion" onClick={this.addTextQuestion}>
          <i className="material-icons">add</i>
          Question
        </button>

      </div>
    );
  }
}

export default QuizBuilder;

添加文本问题

import React from 'react';
import '../css/addQuestion.css';
import AnswerText from './answerText.js';

class AddTextQuestion extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      noAnswers: 0,
    };
    this.addAnswer = this.addAnswer.bind(this);
    this.deleteAnswer = this.deleteAnswer.bind(this);
  }

  addAnswer() {
    this.setState({
      noAnswers: this.state.noAnswers + 1,
    });
  }

  deleteAnswer(num) {
    delete this.answers[num];

    this.setState({
      noAnswers: this.state.noAnswers - 1,
    });
  }

  render() {

    const answerButton = this.state.noAnswers < 4 ?
      <button type="button" onClick={this.addAnswer}><i className="material-icons">add</i>Answer
      </button> : <button type="button">Max of 4 answers</button>;

    let answers = [];

    for(let i = 0; i < this.state.noAnswers; i++) {
      answers.push(<div key={i}>
        <AnswerText qNo={i + 1}/>
        <button type="button" id={`delet_${i}`} onClick={}>X</button>
        {console.log(i)}
      </div>);
    }

    return (
      <div className="qContainer">

        <div className="questionContainer containers">
          <h3 className="qNo">Question {this.props.qNo}</h3>
          <div className="input">
            <label htmlFor="question">Question</label>
            <input name="question" type="text" id="question"></input>
          </div>
        </div>

        <div className="answerContainer containers">
          {answers}
          {answerButton}

        </div>
      </div>
    );
  }
}

export default AddTextQuestion;

AnswerText

import React from 'react';

class AnswerText extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="input">
        <label htmlFor="answer1">Answer {this.props.qNo}</label>
        <input name="answer1    " type="text" id={`answer_${this.props.qNo}`}></input>
        <input type="radio" name="answerCheck" id="answerCheck"></input>
      </div>
    );
  }
}

export default AnswerText;

对于如何最好地解决这个问题,我们将不胜感激。这是最令人沮丧的!

【问题讨论】:

  • 由于某种原因,一些代码似乎已经消失了,但希望你们能明白其中的要点。

标签: javascript reactjs react-native components frontend


【解决方案1】:

问题似乎在于定义状态的方式。这是一个难题,所以答案很长。

首先,React 中有两种方法可以创建表单并从中收集数据:

  • 使用受控组件 (recommended)
  • 使用不受控制的组件(您在上面使用的那个)。

我们将坚持使用您示例中的非受控组件,但阅读受控组件以了解这两种方法。

只有noQuestions: 0 和noAnswers: 0 不足以支持任何元素的添加和删除。您需要使用数组:questions: [] 和 answers: []。

这些数组中会有 ID。对于删除操作,每个问题和每个答案都需要一个唯一的 ID。一个简单的数字就可以了。

例如,从answers: [] 状态开始,我们需要在单击添加按钮时将状态设置为answers: [1],并在再次单击时将状态设置为answers: [1, 2]。

现在您可以通过将答案 1 或答案 2 从 answers 数组中过滤出来来删除它。例如,当第一个答案被删除时导致answers: [2]。

这是AddTextQuestion 类的代码:

class AddTextQuestion extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            answers: [],
        }
        this.addAnswer = this.addAnswer.bind(this);
        this.deleteAnswer = this.deleteAnswer.bind(this);
    }

    addAnswer() {
        const len = this.state.answers.length;
        // an ID will be last ID + 1 or 1 if array is empty
        const newNum = len ? (this.state.answers[len - 1] + 1) : 1;
        this.setState({
            // add newNum to answers and save the result to state
            answers: this.state.answers.concat(newNum),
        })
    }

    deleteAnswer(num) {
        this.setState({
            // create new copy of answers without 'num' and save to state
            answers: this.state.answers.filter(ans => ans !== num),
        })
    }

    render() {

        const answerButton = this.state.answers.length < 4 ? <button type="button" onClick={this.addAnswer}><i className="material-icons">add</i>Answer</button> : <button type="button">Max of 4 answers</button>

        let answers = []; // unrelated to this.state.answers

        for (let i = 0; i < this.state.answers.length; i++) {
            answers.push(<div key={this.state.answers[i]}>
                <AnswerText qNo={this.props.qNo} ansNo={i + 1} />
                <button
                    type="button"
                    onClick={() => this.deleteAnswer(this.state.answers[i])}
                >X</button>
            </div>);
        }

        const uniqueId = `question-${this.props.qNo}`;

        return (
            <div className="qContainer">

                <div className="questionContainer containers">
                    <h3 className="qNo">Question {this.props.qNo}</h3>
                    <div className="input">
                        <label htmlFor={uniqueId}>Question</label>
                        <input name={uniqueId} type="text" id={uniqueId}></input>
                    </div>
                </div>

                <div className="answerContainer containers">
                    {answers}
                    {answerButton}

                </div>
            </div>
        );
    }
}

这是AddTextQuestion 类的代码,具有类似的状态变化:

class QuizBuilder extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            questions: []
        };
        this.addTextQuestion = this.addTextQuestion.bind(this);
        this.deleteTextQuestion = this.deleteTextQuestion.bind(this);
    }

    addTextQuestion() {
        const len = this.state.questions.length;
        // an ID will be last ID + 1 or 1 if array is empty
        const newNum = len ? (this.state.questions[len - 1] + 1) : 1;
        this.setState({
            questions: this.state.questions.concat(newNum),
        });
    }

    deleteTextQuestion(num) {
        this.setState({
            questions: this.state.questions.filter(q => q !== num),
        })
    }

    render() {
        let children = [];

        for (let i = 0; i < this.state.questions.length; i++) {
            children.push(<AddTextQuestion key={this.state.questions[i]} qNo={i + 1} />)
        }

        return (
            <form>
                <h2 className="builderHeader">Quiz Builder</h2>
                <div className="questionDiv" id="newQuestionContainer"></div>
                <form className="addQForm">
                    {children}
                </form>
                <button type="button" id="addQuestion" onClick={this.addTextQuestion}><i className="material-icons">add</i> Question</button>

            </form>
        )
    }
}

每个元素都需要通过唯一的 ID 来标识,以便您可以收集输入的数据并保存(例如,但使用 &lt;form&gt; 标记包装您的应用程序)。

Question 1
[ Text ]  (id: question-1)
  Answer 1
   [ Text ] (id: question-1-answer-1) (radio button) (id: question-1-answer)
  Answer 2
   [ Text ]  (id: question-1-answer-2) (radio button) (id: question-1-answer)
  Answer 3
   [ Text ]  (id: question-1-answer-3) (radio button) (id: question-1-answer)

Question 2
[ Text ]  (id: question-2)
  Answer 1
   [ Text ] (id: question-2-answer-1) (radio button) (id: question-2-answer)
  Answer 2
   [ Text ] (id: question-2-answer-2) (radio button) (id: question-2-answer)
  Answer 3
   [ Text ] (id: question-2-answer-3) (radio button) (id: question-2-answer)

所以这是新的AnswerText 类,带有qNo 和ansNo 道具:

class AnswerText extends React.Component {
    render() {
        const uniqueId = `question-${this.props.qNo}-answer-${this.props.ansNo}`;

        return (
            <div className="input">
                <label htmlFor={uniqueId}>Answer {this.props.ansNo}</label>
                <input name={uniqueId} type="text" id={uniqueId} />
                <input type="radio" name={`question-${this.props.qNo}-answer`} value={uniqueId} />
            </div>
        )
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-14
    • 2020-05-23
    • 2019-02-20
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多