9

The problem is that the component is being rendered twice, once with the initial state, again after the setState method in axios promise. Why is this happening and how can I solve this.

I have used both componentWillMount and componentDidMount. I, being a noob, tried hard and failed to figure out why.

export default class Dashboard extends Component{

  constructor(props) {
    super(props)
    this.state = {
      data: {
        okay: 'lul'
      }
    }
  }

  componentWillMount() {
    axios
      .get('/api/data?param1='+this.props.location.state.param1+'&param2='+this.props.location.state.param2)
      .then(res => {
        if (res.status != 401) {
          if(res.err)
            console.log('Error while retrieving: ', res.err)
          else {
            this.setState({
              data: res.data.data
            })
          }
        } else {
          console.log('Unauthorized!');
        }
      })
  }

  render() {
    return (
        <Segment inverted vertical>
          <CardContainer data={this.state.data}/>
        </Segment>
    )
  }
}

Even basic suggestions related to react / JS / general programming is highly appreciated

psvs
  • 199
  • 1
  • 4
  • 14
  • Why do you think it's a problem? If you don't want to show anything before the data has been fetched, you can check `this.state.data` in the render method and return `null` if there's no data to show yet. `setState` will cause the `render` method to be called each time. – Håken Lid May 02 '18 at 09:53
  • @HåkenLid The solution that you've proposed works perfectly. But how can I render the component only once with the correct data? Shall I have to write the axios request inside the constructor and then set the initial state ? – psvs May 02 '18 at 10:13
  • This behaviour is how react is supposed to work. It's not a bug. Calling `render` is really quite cheap, since react will take care of updating the dom in a efficient manner. In some cases you might want to tweak when rerendering happens. This is discussed in the react documentation here: [shouldComponentUpdate In Action](https://reactjs.org/docs/optimizing-performance.html#shouldcomponentupdate-in-action) – Håken Lid May 02 '18 at 10:32

1 Answers1

10

You have a async request in componentWillMount, so before the request is completed, your component is rendered, however once the async request is successful you have a setState function call which triggers a re-render and hence your component is getting rendered twice

This is an expected behaviour.

You can check this question for more details

Use componentWillMount or componentDidMount lifecycle functions for async request in React

According to the docs

componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering.

This means that if you write

componentWillMount() {
   this.setState({count: 1});
}

the state will be reflected in the initial render itself and no-render is triggered. However if you have a async method then calling setState inside it might trigger an extra render if the async request gets completed after the render is already called.

To emphasize more on the fact, you must not use componentWillMount any more, since React is oncourse to remove this method from future major realease. Instead use componentDidMount.

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • I got you. So, whenever state is being set, render method invokes. But they say that the react is "intelligent", doesn't do the redundant rendering. What do you say? – psvs May 02 '18 at 10:18
  • React doesn't do redundant rendering in the dom, but it still calls the render method, it is here that it does a virutal DOM diffing and decides whether to render or not. – Shubham Khatri May 02 '18 at 10:27
  • It was written "Calling setState() in this method will trigger an extra rendering, but it is guaranteed to flush during the same tick. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state". I only have two instances of state, initial and the setState. Is intermediate state is initial one? – psvs May 02 '18 at 10:28
  • calling setState synchronously in componentWillMount won't trigger an extra rendering, but since you have an extra async method here, it does trigger an extra re-render – Shubham Khatri May 02 '18 at 10:29