Changing value of class variable doesn't update the HTML tag bound to it in React

时间:2018-09-22 22:54:47

标签: javascript reactjs typescript rxjs

I've designed the following class.

export default class DataView extends React.Component {

  private message = "---";
  private url = ...;
  private body = { ... };
  private headers = { ... };

  constructor(props: any) {
    super(props);
    this.message = "executing...";

    ajax.post(this.url, this.body, this.headers)
      .subscribe(
        result => {
          this.message = "code " + result.status;
          console.log(result.status);
        },
        error => {
          this.message = "Problem: " + error.status;
          console.log("Problem: " + error.status)
        });
  }

  render() {
    return (
      <div style={divStyle}>
        Message: {this.message}
      </div>);
  }
}

The expectation was that the original string would be replaced with the initial message (which happens) and then, the result of the call (which doesn't happen). I'm new to React and not sure what's wrong here. This is the approach I'm using in Angular but, of course, things work a bit differently in React.

The call itself is a success and I can see the correct results in the console. It's only the binding between the class variable and the rendered value that's stale. I've been told that the rendering's done automagically and I should not call render() myself.

2 个答案:

答案 0 :(得分:2)

React doesn't work like that. It only triggers a new render if you change your state, which you do via setState. Your message property isn't state, and you're not changing it via setState.

Also, triggering ajax from the constructor isn't how you'd do that in React. Instead, you'd do it in componentDidMount, and you'd allow for the fact that the ajax call won't always be complete in render. (If that's not acceptable, then you push the ajax call up a level and have the parent only render this component when the data is available.)

Here's an example with minimal modifications and setTimeout standing in for ajax; see *** comments:

class DataView extends React.Component {

  /* These would all probably be state properties
  private message = "---";
  private url = ...;
  private body = { ... };
  private headers = { ... };
  */

  constructor(props) {
    super(props);
    this.state = {                                  // *** Put `message`
        message: "executing..."                     // *** on `state`
    };
  }
  
  componentDidMount() {                             // *** Use `componentDidMount`
    /*                                              // *** to start async load
    ajax.post(this.url, this.body, this.headers)
      .subscribe(
        result => {
          this.message = "code " + result.status;
          console.log(result.status);
        },
        error => {
          this.message = "Problem: " + error.status;
          console.log("Problem: " + error.status)
        });
    */
    setTimeout(() => {
        this.setState({                             // *** Update state with
            message: "code GOTSTATE"                // *** `setState`
        });
    }, 800);
  }

  render() {
    return (
      // *** No idea where `divStyle` was meant to come from, left it out below
      // Note using `this.state.message` below
      <div>
        Message: {this.state.message}
      </div>);
  }
}


ReactDOM.render(
  <DataView />,
  document.getElementById("root")
);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>

答案 1 :(得分:1)

如果要在ajax调用后重新呈现数据,则应使用state。查看状态和生命周期教程。您的代码应如下所示:

t_steps