dorkycam
dorkycam

Reputation: 529

State Array not updating correctly when adding new item React?

Here's my code:

var questionsList = []

class PhotoDropZone extends Component {
  render() {
    return (
      <div id="dropZone">
        Drop a photo here.
      </div>
    );
  }
}

class Answers extends Component {

  constructor(props) {
    super(props);
    this.state = {
      answers: Array(4).fill(""),
      correctAnswers: [],
    };
    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
    }));

    console.log(event);
  }

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

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

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    this.setState((previousState, props) => ({
      answer: value
    }));
    this.props.onUpdate({
      index: this.props.number,
      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}/>
      </div>
    )
  }
}


var questionIdx = 0;

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

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

    console.log(event);
  }

  addQuestion = question => {
    questionIdx++;
    this.setState(prevState => ({
      questions: [...prevState.questions, question]
    }));
  };

  removeQuestion () {
    console.log("remove button");
  }

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

class Question extends Component {
  constructor(props){
    super(props);
    this.state = {
      question: ""
    }
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    this.setState((previousState, props) => ({
      question: value
    }));
      this.props.onUpdate({
        index: questionIdx,
        value
      });
  }

  render () {
    return (
      <div id={"questionDiv" + questionIdx}>
        Question<br />
        <input type="text" value={this.state.question} onChange={this.handleChange} />
        <PhotoDropZone />
        <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(
      <Question onUpdate={this.handleUpdate} value={this.value} number={this.index}/>
    );
  };

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

class RemoveQuestionButton extends Component {

  removeQuestion = () => {
    this.props.onClick(
      <Question onUpdate={this.handleUpdate} number={questionIdx}/>
    );
  }

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

class BuilderForm extends Component {
  render() {
    return (
      <div id="formDiv">
        <IntroFields />
        <Questions />
      </div>
    );
  }
}
export default BuilderForm;

So this is a form that has an Add Question button that adds a whole section of a form to the form. I am having an issue with my questions and question states. When I add the initial question and start typing in my Question input, another section is added (as if the Add Question button was pressed again) and I notice that two items are added to my questions array, one more object array and a string of what I typed in. Every time I click the Add Question button another object array thing is added to the questions array and it doesn't matter which "Question" input I type in, the string object (inside of the questions array) is updated. Ideally each section of the form would update its own state.

I am not sure why this is happening, I am new to React and JS so even a little explanation of what you think is going on would be very insightful.

If you need more explanation just let me know and I will try my best to explain. I've tried to get this on CodePen and other things but I am never successful at doing so. Thanks ahead of time.

UPDATE: I was able to get it on CodeSandbox

Upvotes: 1

Views: 494

Answers (1)

Tholle
Tholle

Reputation: 112787

questionIdx will be 1 larger than expected, so it will create a new question when used.

Use this.props.number instead in the handleUpdate method of the Question component.

handleChange(event) {
  const target = event.target;
  const value = target.type === "checkbox" ? target.checked : target.value;
  this.setState({
    question: value
  });
  this.props.onUpdate({
    index: this.props.number,
    value
  });
}

Upvotes: 2

Related Questions