5

I using React to implemented Include component. It load content from url. This test works but also produces an unexpected infinite loop with render... why?

<script type="text/jsx">
  /** @jsx React.DOM */
  var Include = React.createClass({
    getInitialState: function() {
      return {content: 'loading...'};
    },
    render: function() {
      var url = this.props.src;
      $.ajax({
        url: url,
        success: function(data) {
          this.setState({content: data});
        }.bind(this)
      });
      return <div>{this.state.content + new Date().getTime()}</div>;
    }
  });

  var Hello = React.createClass({
    render: function() {
        return <Include src="hello.txt" />;
    }
  });
  React.renderComponent(
    <Hello />,
    document.getElementById('hello')
  );
</script>

2 Answers 2

4

This is a more reliable Include component. The differences,

  • render should be pure (can't do ajax there)
  • getInitialState should be pure
  • if the prop is dynamic, e.g. <Include url={this.state.x} />, it should update
var Include = React.createClass({
  getInitialState: function() {
    return {content: 'loading...'};
  },
  componentDidMount: function(){ 
    this.updateAJAX(this.props.url); 
  },
  componentWillReceiveProps: function(nextProps){
    // see if it actually changed
    if (nextProps.url !== this.props.url) {
      // show loading again
      this.setState(this.getInitialState);

      this.updateAJAX(nextProps.url);
    }
  },
  updateAJAX: function(url){
    $.ajax({
      url: url,
      success: function(data) {
        this.setState({content: data});
      }.bind(this)
    });
  },
  render: function() {
    return <div>{this.state.content}</div>;
  }
});

var Hello = React.createClass({
  render: function() {
    return <Include src="hello.txt" />;
  }
});
Sign up to request clarification or add additional context in comments.

Comments

1

I realized render is executed a lot of times, so is not better place to my ajax invocation (-_-)'

This way works fine:

<script type="text/jsx">
  /** @jsx React.DOM */
  var Include = React.createClass({
    getInitialState: function() {
      var url = this.props.src;
      $.ajax({
        url: url,
        success: function(data) {
          this.setState({content: data});
        }.bind(this)
      });
      return {content: 'loading...'};
    },
    render: function() {
      return <div>{this.state.content + new Date().getTime()}</div>;
    }
  });

  var Hello = React.createClass({
    render: function() {
        return <Include src="hello.txt" />;
    }
  });
  React.renderComponent(
    <Hello />,
    document.getElementById('hello')
  );
</script>

Thank you for reading!

3 Comments

Glad to see you worked out the problem! One small suggestion I'd recommend is to move the ajax call into the componentWillMount method. The result is the same but using the componentWillMount method results in better seperation of concerns. I've attached a fiddle so you can what I mean. P.s - React is awesome Here's the jsfiddle
@user3508122 I believe componentDidMount is correct for this. It's used in the official tutorial. The only reason I can think of, is that componentWillMount is called when using renderComponentToString (i.e. server rendering).
@FakeRainBrigand - Good spot! You are correct - my mistake.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.