2

Here's my problem:

I'm new at reactjs and I'm trying to make this app using SWAPI (swapi.co). For now I need to list characters and some info about them. The problem is I have this component called SelectedCharacter that returns some info about a character that was selected in a div.

The moment a character is passed through props to this component, I get a response via xmlhttp and the info is displayed. The thing is that I want to put a "Loading..." message while the data is fetched. This is how I was trying to figure it out:

I set up the componentWillReceiveProps function, where I test if I'll need to load stuff and the componentDidUpdate, where I fetch the data from this api and update the status.

I know, from react life cycle, that a render is called between componentWillReceiveProps and componentDidUpdate, and it indeed is.

I expected, then, that if I did this:

render() {
  if (criteria) {
    return <div>Loading...</div>
  }
}

The thing is: even if this criteria is true (I tested it using console.log()), the message doesn't show until the next re-render. Am I doing anything too wrong here? If it helps, my code is at github.com/piubellofelipe/StarWars, the problem is at the selected_characters.js, in the src paste.

Thanks

Austin Greco
  • 32,997
  • 6
  • 55
  • 59

1 Answers1

0

I've been looking at your code, trying to work this out for you and I don't have any concrete answers for you, but I've noticed a few things that may be making things a bit unpredictable.


1. Calling forceUpdate

componentWillReceiveProps(){
    this.setState({loading:true})
    this.forceUpdate();
}

Calling setState will trigger a render, so the call the forceUpdate is not required here. This means there are more renders occurring than you might expect.

I believe this may be the cause of your issue for a pretty complicated reason. From the setState docs

... setState() is also asynchronous, and multiple calls during the same cycle may be batched together.

And from the forceUpdate docs

Calling forceUpdate() will cause render() to be called on the component...

My theory is that the call render triggered by setState, asynchronously setting loading to true, is being delayed and the one from forceUpdate is sneaking in first, while loading is still false.

2. Updating props

this.props.selected.moviesList = moviesListNames;

Components should never, ever, update their own props. Usually, this would be stored in state instead.

For more details on this, read this section of the docs and this answer.

3. Importing axios, but not using it

import axios from 'axios'

This one isn't really an issue (other than an unused import), and might just be preparation for where you're heading. axios gives a much nicer developer experience than XMLHttpRequest (in my opinion) for http requests and will clean up the fetchData function a lot, which will make troubleshooting easier.


I hope this helps a bit, and you're enjoying React. Feel free to follow up on any of these points in the comments or as new questions.

Michael Peyper
  • 6,814
  • 2
  • 27
  • 44