Dhoni
Dhoni

Reputation: 1234

ReactJS: In which order the code in each component runs?

I made an API call in componentDidMount for the below component structure. But console.log("SAS",this.props.courses) this line in CourseCardGroup is printed twice with empty value for 1st time and with returned values form API for 2nd time as shown in Image below. How to make it work for first time with data from API call?

Thanks in advance.

enter image description here

var {Router, Link, Route, hashHistory} = require('react-router');

var CourseCard = React.createClass({
  render: function() {
    return(
          <h4>{this.props.each_course.course_name}</h4>
      );
  }
});

var CourseCardGroup = React.createClass({
  render : function() {
    var props = this.props;
    console.log("SAS",this.props.courses)
    var all_course_cards = this.props.courses
      .map(function(each_course){
        return(
          <CourseCard key={each_course.course_name} each_course={each_course} />
          );
      });
    return (
      <div>
        {all_course_cards}
      </div>
    );
  }
});

var FilterableCourseGroup = React.createClass({
  render: function() {
    return(
      <div className="sidebar">
        <CourseCardGroup  courses={this.props.courses} />
      </div>
    );
  }
});

const FilterableCourseGroupWrapper = React.createClass({
    getInitialState: function(){
    return{
      all_courses: []
      };
  },
  componentDidMount: function() {
    data = {"k":"coursesdetails"}
    $.post("http://127.0.0.1:8080/QuestionPapers/getcoursedetails/",data , function(result) {
      console.log("Out mounted: ",  result)
      if (this.isMounted()) {
          this.setState({all_courses:result})
          console.log("In mounted: ",  result)  
      }
    }.bind(this));
  },
  render() {
    return (
      <div className="courses_and_papers">
        <FilterableCourseGroup courses={this.state.all_courses}/>
        {this.props.children}
      </div>
      )
  }
})

const App = React.createClass({
  render() {
    return (
      <div>
          <FilterableCourseGroupWrapper/>
          {this.props.children}
      </div>
    )
  }
})


// Finally, we render a <Router> with some <Route>s.
// It does all the fancy routing stuff for us.
ReactDOM.render((
  <Router history={hashHistory}>
    <Route path="/" component={App}>
    </Route>
  </Router>
), document.getElementById("filterable_courses"))

Upvotes: 0

Views: 105

Answers (2)

wintvelt
wintvelt

Reputation: 14101

Your code currently does:

  • getInitialState
  • then render (to display something)
  • then componentDidMount, which make an ajax call to get data
  • when you get response from ajax, you call setState
  • this triggers another render (this time with data)

For the first render (while you still have nothing to display), you typically would have some sort of 'loading' message.

Something like:

var FilterableCourseGroup = React.createClass({
  render: function() {
    if (this.props.courses.length == 0) {
      // return loading message
    } else {
      // now we apparently have courses
      return(
        <div className="sidebar">
          <CourseCardGroup  courses={this.props.courses} />
        </div>
      );
    }
  }
});

Upvotes: 1

gor181
gor181

Reputation: 2068

You are console logging value while in render method therefore you have an empty state or undefined as the ajax is async therefore the value is going to be provided at later time.

Which means that React won't wait for it, but will handle it once it becomes available.

Detailed list of component lifecycle methods is available at: https://facebook.github.io/react/docs/component-specs.html It will provide you with enough information on how those are triggered.

While I would encourage you to read about reconciliation at https://facebook.github.io/react/docs/reconciliation.html

Upvotes: 2

Related Questions