【问题标题】:React - conditional render fails trying to display component for the second timeReact - 条件渲染第二次尝试显示组件失败
【发布时间】:2018-02-05 20:47:45
【问题描述】:

我正在创建一个 React 组件来管理用户输入。 这个组件,UserInput.js,有以下方法,

renderOrigin - 显示一个表单组件,

renderCities - 使用不同的 props 显示相同的表单组件,

renderAddCitiesQuestion - 渲染两个按钮(是或否),由

handleContinue - 使用“继续”问题的答案设置状态

getChildSate - 设置子组件接收到的状态(如表单)

render - 基于状态的条件渲染。 State 具有布尔属性“start”(用于第一次渲染)、“rendercities”和“renderQuestion”。

条件的流程如下。 首先,state.start 为 true,我们调用 renderOrigin; 然后,state.start 变为 false,state.renderCities 变为 true,我们调用 renderCities();然后,state.rendercities 变为 false,state.renderQuestion 变为 true,这使我们调用 renderAddCityQuestion();现在有两种可能性,要么用户单击 No 按钮,我们不应该渲染,要么他单击 Yes 并且 state.renderCities 变为 true (并且 state.renderQuestion 变为 false)调用 renderCities() (它被称为,我通过console.log查看)但该组件未呈现,而问题组件仍然可见。

我看不到错误。 这是完整的代码。

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;

为了完整起见,这里也是 Form 组件。

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;

【问题讨论】:

    标签: reactjs conditional-rendering


    【解决方案1】:

    你更新状态的方式不对,如果你想用新的状态重新渲染组件,你需要使用setState:

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

    很好的解释为什么:https://stackoverflow.com/a/40309023/7132340 还有docs。

    【讨论】:

    • 您的回答是正确的,我很感激,并将其标记为已回答。我想向其他可能遇到此类问题的人指出,我“设置”状态的方式导致控制台显示的状态发生变化。事实上,例如,在执行 console.log(this.state) 时,我可以看到我使用 this.state.cities = true 所做的更改。不知道为什么 react 允许状态更改,但不能很好地处理它
    • 我添加了几个带有 dosc 和解释的链接。
    • @RafaelMarques 确切地说,在您的第一个示例中,重点是 React 不处理更改。做this.state.cities = true 只是一个普通的javascript 对象属性做作。由于 React 是“反应式”的,它不会检查状态是否已更改。使用 this.setState 会将对象修改委托给 React。然后 React 将决定它是否应该重新渲染。
    猜你喜欢
    • 2023-04-04
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 2018-07-20
    • 2022-06-30
    • 2020-08-07
    • 1970-01-01
    • 2019-10-06
    相关资源
    最近更新 更多