0
votes

I am creating a React Component to manage the user Input. This Component, UserInput.js, has the following methods,

renderOrigin - displays a Form component,

renderCities - displays the same form component with diferent props,

renderAddCitiesQuestion - renders two buttons (yes or no) which are handled by,

handleContinue - sets state with the answer to 'continue' question

getChildSate - sets the state received by the child components (like the form)

render - Conditional rendering based on the state. State has the boolean properties, 'start' (for the first render), 'rendercities' and 'renderQuestion'.

The flow of the conditional is as follows. First, state.start is true and we call renderOrigin; than, state.start becomes false, state.renderCities becomes true, and we call renderCities(); than, state.rendercities becomes false and state.renderQuestion becomes true, which makes us call renderAddCityQuestion(); now there are two possibilites, either the user clicks the No button, and we should render nothing, or he clicks Yes and state.renderCities becomes true ( and state.renderQuestion becomes false) which calls renderCities() (and it is called, i see it via console.log) but that component is NOT rendered, while the question component remains visible.

I can not see to find the mistake. Here is the entirety of the code.

import React from 'react';
import Form_city from './Form_city';

class UserInput extends React.Component {
  constructor(props) {
    super(props);
    this.getChildState = this.getChildState.bind(this);
    this.handleContinue = this.handleContinue.bind(this);
    this.renderOrigin = this.renderOrigin.bind(this);
    this.renderCities = this.renderCities.bind(this);
    this.renderAddCitiesQuestion = this.renderAddCitiesQuestion.bind(this);
    this.state = {
      origin: null,
      cities: [],
      renderCities: false,
      renderQuestion: false,
      start: true
    }
  }

  getChildState(stateName, stateVal) {
    console.log('setting state. received stateName, stateVal', stateName, stateVal);
    this.setState({
       [stateName] : stateVal
     });
    console.log('set state done: ', this.state);
  }

  handleContinue(answer) {
    this.state.renderQuestion = false;
    answer === 'yes' ? this.state.renderCities = true : this.state.renderCities = false;
    console.log('state after clicking answer: ', this.state);
    this.render();
  }

  renderOrigin() {
    return(
      <div>
        <Form_city
          divName="originForm"
          text="Please select an Origin:"
          type="origin"
          placeHolder="Origin"
          getChildState={this.getChildState}
        />
      </div>
    );
  }

  renderCities() {
    console.log('rendering city form');
    return(
      <div>
        <Form_city
          divName="citiesForm"
          text="Which city do you want to visit?"
          type="cities"
          placeholder="Destination"
          getChildState={this.getChildState}
        />
      </div>
    );
  }

  renderAddCitiesQuestion() {
    console.log('rendering question');
    return(
      <div>
        <p>Do you want to visit any other city?</p> <br />
        <button type="button" onClick={this.handleContinue.bind(this, 'yes')}>Yes</button>
        <button type="button" onClick={this.handleContinue.bind(this, 'no')}>No</button>
      </div>
    );
  }

  render() {
    console.log('inside render\n, state: ', this.state);
    let content = null;
    if (this.state.start === true) {
      console.log('inside render origin conditional');
      content = this.renderOrigin();
    } else if (this.state.renderCities === true) {
      console.log('inside render cities conditional');
      content = this.renderCities();
    } else if (this.state.renderQuestion === true) {
      console.log('inside render question conditional');
      content = this.renderAddCitiesQuestion();
    } else {
      content = <p>Weird stuff?</p>
    }

    return(
      <div> {content} </div>
    );
  }

}

export default UserInput;

here is also the Form component for completeness sake.

import React from 'react';

class Form_city extends React.Component {
  constructor(props) {
    super(props);
    this.state = {data: ''};
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState( {data: event.target.value} );
  }

  handleSubmit(event) {
    console.log('clicked submit button');
    event.preventDefault();
    if (this.props.type === 'origin') {
      console.log('inside handle submit Origin, passing: ', this.state.data);
      this.props.getChildState('start', false);
      this.props.getChildState('origin', this.state.data);
      this.props.getChildState('renderCities', true);
    } else if (this.props.type === 'cities') {
      console.log('inside handle submit Cities');
      this.props.getChildState('cities', this.state.data);
      this.props.getChildState('renderCities', false);
      this.props.getChildState('renderQuestion', true);
    }

  }

  render() {
    return(
      <div className = {this.props.divName}>
        <form onSubmit = {this.handleSubmit}>
          <label>
            {this.props.text} <br />
            <input
              type="text"
              placeholder={this.props.placeholder}
              value={this.state.data}
              onChange={this.handleChange}
            />
          </label>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default Form_city;
1

1 Answers

2
votes

Your way to update a state is incorrect, you need to use setState if you want to re-render component with a new state:

  handleContinue(answer) {
    if (answer === 'yes'){
        this.setState({
            renderQuestion: false,
            renderCities: true,
            renderCities: false
        })
    }
  }

Pretty good explanation why: https://stackoverflow.com/a/40309023/7132340 And docs.