在更新父级状态时更新子级中的选项列表

时间:2019-07-09 12:02:56

标签: reactjs react-props react-state

我基于所选课程的选项(域)列表在父级状态下更新,但子级不会更新/继承随其发送的道具。子级需要从父级接收域状态,并从中组成一个选项列表。它可用于初始化,但在父组件中更改路线后将不会更新。

AddQuestion.js

class AddQuestion extends Component {

  constructor(props){
      super(props)

      // initiate all states
      this.state = {
        course: '',
        domains: []
      }

  }
  render() {
    return (
      <MainQuestion formError={this.state.formError} levels={this.state.levels} years={this.state.years} courses={this.state.courses} introductionlist={this.state.introductionlist} subQuestions={this.state.subQuestions} numSubQuestion={this.state.numSubQuestion} handleCourseChange={this.handleCourseChange} postQuestion={this.postQuestion} addSubQuestion={this.addSubQuestion} formHasError={this.state.formHasError} validateForm={this.validateForm}/>
    );
  }

  // handle onchange course input
  handleCourseChange = (e) => {
     this.setState({
       course: e.target.value
     },
     function(e) {
      console.log(this.state.course);
      this.getResponseDomains();
      },
     this.validateForm(e)
   );
  }

  // get domains based on course
  getResponseDomains = () => {

    console.log(this.state.course);
    // fetch data from backend
    axios.get('/api/domain/get?course=' + this.state.course, {
      course: this.state.course
    })
    .then(response => response.data.data)
    .then((json) => {

      json.map(obj => this.setState({domains: Object.values(obj) }));
      this.state.domains = json;

      // map a option input for each fetched domain
      let domainslist = Object.keys(this.state.domains).map(key =>
        <option label={this.state.domains[key].name} value={this.state.domains[key].id} />
      )

      this.setState({
        domains: domainslist
      });

    })
    .catch((error) => {
      console.log(error);
    });
  }

  // Add the input field to a new subquestion
  addSubQuestion = () => {
    this.setState({
      numSubQuestion: this.state.numSubQuestion + 1,
      formHasError: true
    });

    //reset array
    subQuestions = [];

    let errormessages = '';
    let errornum = this.state.numSubQuestion + 1;

    //fill array for amount of subquestions needed
    for (var i = 0; i <= this.state.numSubQuestion; i += 1) {
      subQuestions.push(<SubQuestion key={i} number={i + 1} domain={this.state.domain} course={this.state.course} domains={this.state.domains} subjects={this.state.subjects} />);

    this.setState({
      subQuestions: subQuestions,
      formError: errormessages
    });

  }

MainQuestion.js

// This is the main question (e.d. level, year, course and introduction)
class MainQuestion extends Component {

  constructor(props){
      super(props)

  }
  render() {
    return (
      <div className="addQuestion-wrapper">
        <div className="logo mx-auto">
          <img src="/img/logo-white.png"/>
        </div>
        <section className="addQuestion container">
          <form id="addQuestionForm">
            <p className="text-danger">{ this.props.formError }</p> {/* display errors */}
            <div className="row d-flex prequestion">
              <div className="col-12 mb-3">
                <h2>Nieuwe vraag toevoegen</h2>
              </div>
              <div ref="error3" className="input-group col-12 col-lg-6" id="levels-wrapper">
                <div>
                  <p className="label">Niveau</p>
                  {this.props.levels} {/* display fetched levels */}
                </div>
              </div>
              <div ref="error4" className="input-group col-12 col-lg-6" id="years-wrapper">
                <div>
                  <p className="label">Leerjaar</p>
                  {this.props.years} {/* display fetched years */}
                </div>
              </div>
              <div ref="error5" className="input-group col-12 col-lg-6">
              <p className="label">Vak</p>
                <select onChange={this.props.handleCourseChange} name="course" id="select-courses">
                  <option value="" disabled selected>--Kies een vak</option>
                  {this.props.courses} {/* display fetched courses */}
                </select>
              </div>
              <div ref="error10" className="input-group col-12 col-lg-12">
                {this.props.introductionlist} {/* display created introduction textarea */}
              </div>

              </div>

              { this.props.subQuestions } {/* display amount of subquestions in the array */}

              {/* add subquestion button */}
              <div className="AddSubquestion">
                <button className="btn" onClick={ this.props.addSubQuestion } disabled={this.props.formHasError}>Subvraag toevoegen</button>
              </div>

              {/* post question button */}
              <div className="input-group" id="submit">
                <button className="btn" onClick={ this.props.postQuestion } value="Aanmaken" disabled={this.props.formHasError}>Verzend</button>
              </div>

          </form>
        </section>
      </div>
    );
  }



}

export default AddQuestion;

SubQuestion.js

class SubQuestion extends Component {

  constructor(props){
      super(props)

      // initiate all states
      this.state = {
        course: props.course,
        domains: []
      }

  }

  render() {
    return (
      <div className="row d-flex justify-content-center question mt-5">
        <div className="col-12">
          <h3> Subvraag {this.props.number} </h3> {/* display number of subquestion. Fetched from key of created child component */}
        </div>
        <div ref="error" className="input-group col-12 col-lg-6" id="type-wrapper">
          {this.state.type} {/* display fetched type */}
        </div>
        <div ref="error2" className="input-group col-12 col-lg-6" id="questionings-wrapper">
          <div>
            <p className="label">Vraagstelling</p>
            {this.state.questionings} {/* display fetched questionings */}
          </div>
        </div>
        <div ref="error6" className="input-group col-12 col-lg-12">
          {this.state.question} {/* display created textarea for questiona AND answer */}
        </div>
        <div ref="error7" className="input-group col-12 col-lg-6">
          <p className="label">Domein</p>
          <select id="select-domains" name={`domain-${this.props.number}`} onChange={this.handleDomainChange}>
            <option value="" disabled selected>--Kies een domein</option>
            {this.props.domains} {/* display fetched domains */}
          </select>
        </div>
        <div ref="error8" className="input-group col-12 col-lg-6" id="select-subjects">
          <p className="label">Onderwerp</p>
          <select onChange={this.props.handleSubjectChange} name={`subject-${this.props.number}`}>
            <option value="" disabled selected>--Kies een onderwerp</option>
            {this.state.subjects} {/* display fetched subjects */}
          </select>
        </div>
        <div ref="error9" className="input-group col-12 col-lg-12" id="time-points-rtti">
          <div className="time mr-4">
            {/* display time input */}
            <p className="label">Tijdsduur</p>
            <input type="number" name={`tijdsduur-${this.props.number}`} min="1" placeholder="tijd in minuten" onChange={this.props.handleTimeChange}/>
          </div>
          <div className="points mr-4">
            {/* display points input */}
            <p className="label">Punten</p>
            <input type="number" name={`points-${this.props.number}`} min="1" placeholder="punten" onChange={this.props.handlePointsChange}/>
          </div>
          <div className="rtti">
            {/* display rtti input */}
            <p className="label">RTTI</p>
            <input type="radio" name={`RTTI-${this.props.number}`} id={`R-${this.props.number}`} value="1" onChange={this.props.handleRttiChange}/><label htmlFor={`R-${this.props.number}`}>R</label>
            <input type="radio" name={`RTTI-${this.props.number}`} id={`T1-${this.props.number}`} value="2" onChange={this.props.handleRttiChange}/><label htmlFor={`T1-${this.props.number}`}>T1</label>
            <input type="radio" name={`RTTI-${this.props.number}`} id={`T2-${this.props.number}`} value="3" onChange={this.props.handleRttiChange}/><label htmlFor={`T2-${this.props.number}`}>T2</label>
            <input type="radio" name={`RTTI-${this.props.number}`} id={`I-${this.props.number}`} value="4" onChange={this.props.handleRttiChange}/><label htmlFor={`I-${this.props.number}`}>I</label>
          </div>
        </div>
      </div>

    );
  }

  componentWillReceiveProps(nextProps) {
      this.setState({course: nextProps.course, domains: nextProps.domains });
  }

// handle onchange domain input
  handleDomainChange = (e) => {
     this.setState({
       domain: e.target.value
     },
     this.getResponseSubjects, // change subjects based on selected domain
     this.props.validateForm(e)
    );
  }

  // get subjects based on domain
  getResponseSubjects = () => {

    // fetch data from backend
    axios.get('/api/subject/get?domain=' + this.state.domain, {
      domain: this.state.domain
    })
    .then(response => response.data.data)
    .then((json) => {

      json.map(obj => this.setState({subjects: Object.values(obj) }));
      this.state.subjects = json;

      // map a option input for each fetched subject
      let subjectslist = Object.keys(this.state.subjects).map(key =>
        <option label={this.state.subjects[key].name} value={this.state.subjects[key].id} />
      )

      this.setState({
        subjects: subjectslist
      }
      );

    })
    .catch((error) => {
      console.log(error);
    });
  }

export default SubQuestion;

预期结果是子组件根据课程更改域。这些变量在父级AddQuestion上更改,但在子级中不作为prop来实现。

2 个答案:

答案 0 :(得分:0)

乍一看,您正在这样做:

handleCourseChange = (e) => {
     this.setState({
       course: e.target.value
     },
     function(e) {
      console.log(this.state.course);
      this.getResponseDomains();
      },
     this.validateForm(e)
   );
  }

如果我是对的,则setState之后的回调不知道this是什么,因为您声明的是完整功能而不是箭头功能。常规函数不会继承this,它们在默认情况下是未定义的。

答案 1 :(得分:0)

我通过在handleCourseChange()上调用addSubQuestion函数来修复它。这迫使子问题重新呈现。

相关问题