setState inside a loop - React

旧城冷巷雨未停 提交于 2019-12-23 04:09:36

问题


I am trying to build a questionnaire in react. For now, all my answers will be accepted using the textbox. These will then be sent to my api using the ajax call. I want my params to have following structure,

questionnaire: {
                {question: "question", answer: "answer"},
                {question: "question2", answer: "answer2"},
                {question: "question3", answer: "answer3"}
               }

My code so far is really messy but somehow i'm getting the desired results. However, i'm unable to update the state of my answer and keep getting the Uncaught TypeError: Cannot read property 'setState' of undefined

import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom';
import SubmitButton from '../components/SubmitButton'

export default class QuestionaireContainer extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = { q: this.props.data,
                   questionaire: [],
                 };
  }
  componentDidMount() {
    var q = this.state.q
    var questionaire = this.state.questionaire
    q.map(function(map){
      questionaire.push({"id": map.id,
                         "question": map.question,
                         "answer": '',
                        });
    })
    this.setState({questionaire: questionaire})
  }

  submit(e){
    e.preventDefault();
    var data = {
      questionaires: this.state.questionaire
    }
    $.ajax({
      type: "GET",
      url: "/questionaries/save_questions",
      data: data,
      dataType: 'JSON',
      success: ()=>{
        alert("hello")
      }
    })
  }


  render() {
    var questionNodes = this.state.questionaire.map(function(question){

      var updateTextBox = (e) => {
      console.log(question.answer);
      this.setState({"answer": e.target.value});
      }

      return (
        <li key={question.id}>
          <div className="box-sed">
            <div className="que-set registration question-type">
              <span className="icon-ahead">
                <i aria-hidden="true" className="fa fa-question-circle"></i>
              </span>
              <h2>{question.question}</h2>
              <p>Lorem Ipsum has been the industry's standard dummy text ever since the 1500's, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p>
            </div>
            <div className="registration question-type">
              <input type="text" placeholder="Type answer" className="input-text" value={question.answer} onChange={updateTextBox} />
            </div>
          </div>
        </li>
      );
    });
    return (
      <div className="question">
        <form onSubmit={this.submit.bind(this)}>
          <ul>
          {questionNodes}
          </ul>
          <SubmitButton/>
        </form>
      </div>
    );
  }
}

Also, the params are a array and not a hash now.I cant figure out how else to set the initial state with my questions. The code might be really dirty but i'have only been able to do this yet.

I might not be making myself very clear so kindly bear with me and drop a comment so i could help you to better understand what i want. Any changes and suggestions will be great. Thanks in advance :)

--UPDATE--

I ended up taking Daniel's advice and put the text box in another react components and called it in the parent one.

Also, i omitted the whole state thing inside loop and moved forward with the this.props. I updated the text box's state in the child component (QuestionaireComponent) and used its state in the parent QuestionaireContainer component using the refs.

Following is my final code that got me working:

QuestionaireContainer.jsx

import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom';
import SubmitButton from '../components/SubmitButton'
import QuestionaireComponent from '../components/QuestionaireComponent'

export default class QuestionaireContainer extends React.Component {

  submit(e){
    e.preventDefault();
    var data = {
      questionaires: []
    }
    this.props.data.map(map => {
      data.questionaires.push(this.refs[map.id].state)
    });
    console.log(data);
    console.log("Done");
  }
  render() {
    var questionNodes = this.props.data.map(questions => {
      return (
        <QuestionaireComponent question={questions.question} key={questions.id} id = {questions.id} ref={questions.id}/>
      );
    });
    return (
      <div className="question">
        <form onSubmit={this.submit.bind(this)}>
          <ul>
          {questionNodes}
          </ul>
          <SubmitButton/>
        </form>
      </div>
    );
  }
}

and QuestionaireComponent.jsx

import React, {PropTypes} from 'react'    
export default class QuestionaireComponent extends React.Component {
  static propTypes = {
    question: PropTypes.string.isRequired,
  };
  constructor(props) {
    super(props);
    this.state = { answer: '',
                   question: this.props.question,
                   id: this.props.id,
                 };
  }
  updateTextBox = (e) => {
    this.setState({answer: e.target.value})
  }
  render() {
    return (
      <li>
        <div className="box-sed">
          <div className="que-set registration question-type">
            <span className="icon-ahead">
              <i aria-hidden="true" className="fa fa-question-circle"></i>
            </span>
            <h2>{this.state.question}</h2>
            <p>Lorem Ipsum has been the industry's standard dummy text ever since the 1500's, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p>
          </div>
          <div className="registration question-type">
            <input type="text" placeholder="Type answer" className="input-text" value={this.state.answer} onChange={this.updateTextBox} />
          </div>
        </div>
      </li>
    );
  }
}

Hope this helps anyone whose looking for something similar.


回答1:


Change this:

var questionNodes = this.state.questionaire.map(function(question){

Into

var questionNodes = this.state.questionaire.map(question => {

Because in your code function(question) override the context variable this.



来源:https://stackoverflow.com/questions/39530695/setstate-inside-a-loop-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!