Javascript 不需要的反应组件重新启动?

Javascript 不需要的反应组件重新启动?,javascript,reactjs,states,Javascript,Reactjs,States,因此,这是一个表单,用户可以在其中添加部分以添加问题(构建测验),我注意到,当我填写答案选项并将文件放入我的dropZone(drop可以工作,但不能正确更新,您可以忽略此项)Answer选项和dropZonererender以及诸如refresh和refresh之类的字段将变为空 我不完全清楚为什么会发生这种情况,我曾尝试研究过类似的问题,但我无法让它发挥作用 我想它可能是我的Questions组件中的addQuestion函数。下面是代码: addQuestion = question

因此,这是一个表单,用户可以在其中添加部分以添加问题(构建测验),我注意到,当我填写
答案选项
并将文件放入我的
dropZone
(drop可以工作,但不能正确更新,您可以忽略此项)
Answer选项
dropZone
rerender以及诸如refresh和refresh之类的字段将变为空

我不完全清楚为什么会发生这种情况,我曾尝试研究过类似的问题,但我无法让它发挥作用

我想它可能是我的
Questions
组件中的
addQuestion
函数。下面是代码:

  addQuestion = question => {
    questionIdx++;
    var newQuestion = { uniqueId: uuid(), question: "" }
    this.setState(prevState => ({
      questions: [...prevState.questions, newQuestion]
    }));
    return { questions: newQuestion }
  };

我对React和Js是新手,所以任何提示/解释都会帮上大忙。谢谢

添加新问题并更新组件状态变量
Questions
Questions(数组类型)时,整个组件(
Questions
及其子组件)将经历一个更新过程,在此过程中,它将重新计算输出DOM树(虚拟DOM)基于新状态,并将其与状态更改前的虚拟DOM进行比较。在“重新发布”任何内容之前,它会检查两个版本的虚拟DOM是否与其他内容不同,如果是,它会尽可能高效地重新发布更改的部分

在您的例子中,重新计算会在许多
问题
中看到许多
答案
组件,并且由于
答案
没有任何道具,因此它基本上是一个新的初始状态渲染,包括4个空输入。我能想到的最简单的解决方案是在
Questions
组件的状态下,确保
this.state.Questions
数组中的每个对象都有一个
answers
属性(对象数组的类型)。在
addQuestion
方法中修改
var newQuestion={uniqueId:uuid(),问题:'}
将此数据包含在与该问题相关的答案中

然后,在呈现每个问题时,将此答案数据(答案数组)作为道具传递给
答案
,然后根据索引(对象或字符串)依次传递给每个
答案
组件。同时,必须将
updateAnswers
方法作为
问题
的道具传递给
答案
答案
,当
答案
的输入字段更改时调用该方法。需要将问题id和答案id传递给此方法,以最终修改现在应存储在
问题
组件状态中的答案数据。我调整了下面沙箱中的代码,使其符合以下要求,尽管我没有确保清除所有损坏:

import React, { Component } from "react";
import "./App.css";

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

class DropZone extends Component {
  constructor(props) {
    super(props);
    this.state = {
      file: "",
      fileId: uuid(),
      className: "dropZone"
    };
    this.handleChange = this.handleChange.bind(this);
    this._onDragEnter = this._onDragEnter.bind(this);
    this._onDragLeave = this._onDragLeave.bind(this);
    this._onDragOver = this._onDragOver.bind(this);
    this._onDrop = this._onDrop.bind(this);
  }

  handleChange(file = "") {
    this.setState({
      file: URL.createObjectURL(file)
    });
    //document.getElementsByClassName("dropZone").style.backgroundImage = 'url(' + this.state.file + ')';
  }

  componentDidMount() {
    window.addEventListener("mouseup", this._onDragLeave);
    window.addEventListener("dragenter", this._onDragEnter);
    window.addEventListener("dragover", this._onDragOver);
    document
      .getElementById("dragbox")
      .addEventListener("dragleave", this._onDragLeave);
    window.addEventListener("drop", this._onDrop);
  }

  componentWillUnmount() {
    window.removeEventListener("mouseup", this._onDragLeave);
    window.removeEventListener("dragenter", this._onDragEnter);
    window.addEventListener("dragover", this._onDragOver);
    document
      .getElementById("dragbox")
      .removeEventListener("dragleave", this._onDragLeave);
    window.removeEventListener("drop", this._onDrop);
  }

  _onDragEnter(e) {
    e.stopPropagation();
    e.preventDefault();
    return false;
  }

  _onDragOver(e) {
    e.preventDefault();
    e.stopPropagation();
    return false;
  }

  _onDragLeave(e) {
    e.stopPropagation();
    e.preventDefault();
    return false;
  }

  _onDrop(e, event) {
    e.preventDefault();
    this.handleChange(e.dataTransfer.files[0]);
    let files = e.dataTransfer.files;
    console.log("Files dropped: ", files);
    // Upload files
    console.log(this.state.file);
    return false;
  }

  render() {
    const uniqueId = this.state.fileId;
    return (
      <div>
        <input
          type="file"
          id={uniqueId}
          name={uniqueId}
          class="inputFile"
          onChange={e => this.handleChange(e.target.files[0])}
        />
        <label htmlFor={uniqueId} value={this.state.file}>
          {this.props.children}
          <div className="dropZone" id="dragbox" onChange={this.handleChange}>
            Drop or Choose File
            <img src={this.state.file} id="pic" name="file" accept="image/*" />
          </div>
        </label>
        <div />
      </div>
    );
  }
}

class Answers extends Component {
  constructor(props) {
    super(props);
    this.state = {
      answers: props.answers,
    };
    this.handleUpdate = this.handleUpdate.bind(this);
  }

  // let event = {
  //   index: 1,
  //   value: 'hello'
  // };
  handleUpdate(event) {
    //if ("1" == 1) // true
    //if ("1" === 1) //false
    // var answers = this.state.answers;
    // answers[event.index] = event.value;
    // this.setState(() => ({
    //   answers: answers
    // }));

    var answers = this.state.answers.slice();

    for (var i = 0; i < answers.length; i++) {
      if (answers[i].answerId == event.answerId) {
        answers[i].answer = event.value;
        break;
      }
    }
    this.setState(() => ({
      answers: answers
    }));
    this.props.updateAnswers(answers)

    console.log(event);
  }

  render() {
    return (
      <div id="answers">
        Answer Choices<br />
        {this.state.answers.map((value, index) => (
          <Answer
            key={`${value}-${index}`}
            onUpdate={this.handleUpdate}
            value={value}
            number={index}
            name="answer"
          />
        ))}
      </div>
    );
  }
}

class Answer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      answer: props.value.answer,
      answerId: props.value.answerId,
      isCorrect: props.value.isCorrect,
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    this.setState({
      answer: value
    });
    this.props.onUpdate({
      answerId: this.state.answerId,
      value
    });

    // let sample = {
    //   kyle: "toast",
    //   cam: "pine"
    // };

    // sample.kyle
    // sample.cam
  }
  render() {
    return (
      <div>
        <input type="checkbox" />
        <input
          type="text"
          value={this.state.answer}
          onChange={this.handleChange}
          key={this.state.answerId}
          name="answer"
        />
        {/*console.log(this.state.answerId)*/}
      </div>
    );
  }
}

var questionIdx = 0;

class Questions extends Component {
  constructor(props) {
    super(props);
    this.state = {
      questions: []
    };
    this.handleUpdate = this.handleUpdate.bind(this);
    this.handleUpdate = this.handleUpdate.bind(this);
    this.removeQuestion = this.removeQuestion.bind(this);
  }

  handleUpdate(event) {
    //if ("1" == 1) // true
    //if ("1" === 1) //false
    var questions = this.state.questions.slice();

    for (var i = 0; i < questions.length; i++) {
      if (questions[i].uniqueId == event.uniqueId) {
        questions[i].question = event.value;
        break;
      }
    }
    this.setState(() => ({
      questions: questions
    }));

    console.log(event, questions);
  }

  updateAnswers(answers, uniqueId) {
    const questions = this.state.questions
    questions.forEach((question) => {
      if (question.uniqueId === uniqueId) {
        question.answers = answers
      }
    })
    this.setState({
      questions,
    })
  }

  addQuestion = question => {
    questionIdx++;
    var newQuestion = { 
      uniqueId: uuid(),
      question: "",
      answers: [
        { answer: "", answerId: uuid(), isCorrect: false,},
        { answer: "", answerId: uuid(), isCorrect: false,},
        { answer: "", answerId: uuid(), isCorrect: false,},
        { answer: "", answerId: uuid(), isCorrect: false,}]
      }
    this.setState(prevState => ({
      questions: [...prevState.questions, newQuestion]
    }));
    return { questions: newQuestion };
  };

  removeQuestion(uniqueId, questions) {
    this.setState(({ questions }) => {
      var questionRemoved = this.state.questions.filter(
        props => props.uniqueId !== uniqueId
      );
      return { questions: questionRemoved };
    });
    console.log(
      "remove button",
      uniqueId,
      JSON.stringify(this.state.questions, null, " ")
    );
  }

  render() {
    return (
      <div id="questions">
        <ol id="quesitonsList">
          {this.state.questions.map((value, index) => (
            <li key={value.uniqueId}>
              {
                <RemoveQuestionButton
                  onClick={this.removeQuestion}
                  value={value.uniqueId}
                />
              }
              {
                <Question
                  onUpdate={this.handleUpdate}
                  value={value}
                  number={index}
                  updateAnswers={(answers) => this.updateAnswers(answers, value.uniqueId) }
                />
              }
              {<br />}
            </li>
          ))}
        </ol>
        <AddQuestionButton onClick={this.addQuestion} />
      </div>
    );
  }
}

class Question extends Component {
  constructor(props) {
    super(props);
    this.state = {
      question: props.value.question,
      uniqueId: props.value.uniqueId,
      answers: props.value.answers,
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    this.setState({
      question: value
    });
    this.props.onUpdate({
      uniqueId: this.state.uniqueId,
      value
    });
  }

  render() {
    return (
      <div id={"questionDiv" + questionIdx} key={myUUID + questionIdx + 1}>
        Question<br />
        <input
          type="text"
          value={this.state.question}
          onChange={this.handleChange}
          key={this.state.uniqueId}
          name="question"
        />
        <DropZone />
        <Answers updateAnswers={this.props.updateAnswers} answers={this.state.answers} />
      </div>
    );
  }
}

class IntroFields extends Component {
  constructor(props) {
    super(props);
    this.state = {
      title: "",
      author: ""
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = target.name;
    console.log([name]);
    this.setState((previousState, props) => ({
      [name]: value
    }));
  }

  render() {
    return (
      <div id="IntroFields">
        Title:{" "}
        <input
          type="text"
          value={this.state.title}
          onChange={this.handleChange}
          name="title"
        />
        Author:{" "}
        <input
          type="text"
          value={this.state.author}
          onChange={this.handleChange}
          name="author"
        />
      </div>
    );
  }
}

class AddQuestionButton extends Component {
  addQuestion = () => {
    this.props.onClick();
  };

  render() {
    return (
      <div id="addQuestionButtonDiv">
        <button id="button" onClick={this.addQuestion} />
        <label id="addQuestionButton" onClick={this.addQuestion}>
          Add Question
        </label>
      </div>
    );
  }
}

class RemoveQuestionButton extends Component {
  removeQuestion = () => {
    this.props.onClick(this.props.value);
  };

  render() {
    return (
      <div id="removeQuestionButtonDiv">
        <button id="button" onClick={this.removeQuestion} key={uuid()} />
        <label
          id="removeQuestionButton"
          onClick={this.removeQuestion}
          key={uuid()}
        >
          Remove Question
        </label>
      </div>
    );
  }
}

class BuilderForm extends Component {
  render() {
    return (
      <div id="formDiv">
        <IntroFields />
        <Questions />
      </div>
    );
  }
}
export default BuilderForm;
import React,{Component}来自“React”;
导入“/App.css”;
var uuid=require(“uuid-v4”);
//生成新的UUID
var myUUID=uuid();
//验证UUID是否为正确的V4格式
uuid.isUUID(myUUID);//真的
类DropZone扩展组件{
建造师(道具){
超级(道具);
此.state={
文件:“”,
fileId:uuid(),
类名:“dropZone”
};
this.handleChange=this.handleChange.bind(this);
this.\u onDragEnter=this.\u onDragEnter.bind(this);
这个;
this.\u onDragOver=this.\u onDragOver.bind(this);
this._onDrop=this._onDrop.bind(this);
}
handleChange(文件=“”){
这是我的国家({
文件:URL.createObjectURL(文件)
});
//document.getElementsByClassName(“dropZone”).style.backgroundImage='url('+this.state.file+');
}
componentDidMount(){
window.addEventListener(“mouseup”,this.\u ondragleef);
window.addEventListener(“dragenter”,本文件);
window.addEventListener(“dragover”,this.\u onDragOver);
文件
.getElementById(“dragbox”)
.addEventListener(“dragleave”,本文件);
window.addEventListener(“drop”,this.\u onDrop);
}
组件将卸载(){
window.removeEventListener(“mouseup”,this.\u ondragleef);
window.removeEventListener(“dragenter”,this.\u onDragEnter);
window.addEventListener(“dragover”,this.\u onDragOver);
文件
.getElementById(“dragbox”)
.removeEventListener(“dragleave”,本._ondragleef);
window.removeEventListener(“drop”,this.\u onDrop);
}
_昂德拉金特(e){
e、 停止传播();
e、 预防默认值();
返回false;
}
_昂德拉戈弗(e){
e、 预防默认值();
e、 停止传播();
返回false;
}
_昂德拉格(e){
e、 停止传播();
e、 预防默认值();
返回false;
}
_昂德罗普(e,事件){
e、 预防默认值();
this.handleChange(e.dataTransfer.files[0]);
让files=e.dataTransfer.files;
log(“已删除的文件:”,文件);
//上传文件
log(this.state.file);
返回false;
}
render(){
const uniqueId=this.state.fileId;
返回(
this.handleChange(e.target.files[0])]
/>
{this.props.children}
删除或选择文件
);
}
}
类扩展组件{
建造师(道具){
超级(道具);
此.state={
答案:道具,答案,
};
this.handleUpdate=this.handleUpdate.bind(this);
}
//让事件={
//索引:1,
//值:“你好”
// };
handleUpdate(事件){
//如果(“1”==1)//true
//如果(“1”==1)//false
//var answers=this.state.answers;
//答案[event.index]=event.value;
//此.setState(()=>({
//答案:答案
// }));
var answers=this.state.answers.slice();
对于(变量i=0;i({
答案:答案
}));
此.props.updateAnswers(答案)
console.log(事件);
}
伦德