1

I've created the component, which passes the function to change its state to the child.

//parent component
setSubject = (id) => {
    this.setState({
        currentSubject: id
    });
}

<Subjects authToken = {this.state.authToken} subjects = {this.state.subjects} setSubject = {this.setSubject} />

//child component
<li onClick={() => this.props.setSubject(subject.id)}>Egzamino programa</li>

That state is passed to another component.

 <Sections authToken = {this.state.authToken} subject = {this.state.currentSubject} />

From there I am using componentDidUpdate() method to handle this change:

componentDidUpdate() {
    if (this.props.subject) {            
        axios.get(`http://localhost:3000/api/subjects/${this.props.subject}/sections?access_token=${this.props.authToken}`)
            .then(response => {
                this.setState({
                    sections: response.data
                })
            }).catch(err => {
                console.log(err)
            })
    }
}

Everything works as expected, BUT when I try to console.log something in Sections component after I've set currentSubject through Subjects component, that console.log executes endless number of times (so is get request, i guess...) It is not goot, is it? And I cannot understand why this happens..

  • Reading through this question may help you out: https://stackoverflow.com/questions/30528348/setstate-inside-of-componentdidupdate. In your code, it looks like `setState` is called on each `componentDidUpdate` which results in a infinite loop. Was there a reason you were using `componentDidUpdate`? – Derek Hopper Dec 28 '17 at 19:42

1 Answers1

0

The bug is in your componentDidUpdate method.

You are updating the state with

   this.setState({ 
     sections: response.data
   })

When you do that, the componentDidUpdate life-cycle method will be called and there you have the endless loop.

You could make a quick fix by using a lock to avoid this issue. But there might be a better design to solve your issue.

The quick fix example:

if (this.props.subject && !this.state.sectionsRequested) {
  this.setState({
    sectionsRequested: true,
  });
  axios.get(`http://localhost:3000/api/subjects/${this.props.subject}/sections?access_token=${this.props.authToken}`)
    .then(response => {
      this.setState({
        sections: response.data,
      });
    })
    .catch(err => {
      console.log(err);
    });
}

It might better to use componentWillReceiveProps for your case. You are interested in getting data based on your this.props.subject value. I can see that because you're using it as part of your url query.

You might be interested in using componentWillReceiveProps and componentDidMount instead of componentDidUpdate

componentDidMount(){
  if(this.props.subject){
    /* code from componentDidUpdate */
  }
}

componentWillReceiveProps(nextProps){
  if(nextProps.subject && this.props.subject !== nextProps.subject){
    /* code from componentDidUpdate */
  }
}
Kunukn
  • 2,136
  • 16
  • 16
  • Issue with this fix: I cannot make get request twice (with another subject.id). Tried using componentWillReceiveProps and now something is wrong with setState when i get axios response. After downloading array of sections, the Id of each section is passed to another component which loads subsections. But subsections does not load after first time componentWillReceiveProps method is called. I guess it is because response is handled with delay, and render happens before the setState. So how to make it render after state is set..? – Donatas Jarmalovicius Dec 28 '17 at 20:52
  • Remember to also use `componentDidMount` to fetch initial data, (in case you didn't use it). React triggers the render method and the children render method for you if you update the state though `setState`. – Kunukn Dec 28 '17 at 20:59
  • Why do I need to use componentDidMount if initial data (subject.id) is not known? I want it to render sections and subsections after I press a button which assigns the value for this.props.subject. Called this.forceUpdate() after setState in axios.get(`***`).then() and everything seems to be working. – Donatas Jarmalovicius Dec 28 '17 at 21:11