Reputation: 39018
When fetchServices()
is called, api.getServices
is called and in the promise this.setState
is called to change fetchingServices
to false
. Which then hides the loading spinner animation.
For some reason the App is stuck in an infinite loop:
constructor(props) {
super(props);
this.state = {
services: props.state.servicesReducer.services,
fetchingServices: true,
addingService: false
}
this.fetchServices = this.fetchServices.bind(this);
}
return (
<div className='services-container'>
<ul className='services-list'>
<li>
<AddServiceContainer />
</li>
{ this.state.fetchingServices
? <div className="icon-spin5 animate-spin"></div>
: null }
{ this.fetchServices() }
</ul>
</div>
)
fetchServices() {
console.log('fetchServices')
api.getServices(12345).then(res => {
console.log(' api.getServices res:', res)
this.setState({
fetchingServices: false
});
});
}
Full code
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { AddServiceContainer } from './AddServiceContainer'
import { ServiceCard } from '../../components'
import { getServices } from '../../actions'
import * as api from '../../services/api'
export class ServicesContainer extends Component {
constructor(props) {
super(props);
this.state = {
services: props.state.servicesReducer.services,
fetchingServices: true,
addingService: false
}
this.fetchServices = this.fetchServices.bind(this);
}
onFormSubmit(e, user) {
e.preventDefault();
this.props.searchUser(user)
}
fetchServices() {
console.log('fetchServices')
api.getServices(12345).then(res => {
console.log(' api.getServices res:', res)
this.setState({
fetchingServices: false
});
});
}
render() {
return (
<div className='services-container'>
<ul className='services-list'>
<li>
<AddServiceContainer />
</li>
{ this.state.fetchingServices
? <div className="icon-spin5 animate-spin"></div>
: null }
{ this.fetchServices() }
</ul>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
state
}
}
const mapDispatchToProps = (dispatch) => {
return {
getServices: (services) => { dispatch(getServices(services)) }
}
}
const ServicesListContainer = ServicesContainer;
export default connect(mapStateToProps, mapDispatchToProps)(ServicesListContainer)
Upvotes: 5
Views: 6210
Reputation: 16472
Whenever you do setState, the render method is called again. Now problem here is that you are calling fetchServices()
method inside the render method. Now whenever fetchServices()
is called it calls an api. When the result of the api come, you are setting the state using setState
, which causes rerender(i.e. your render method is called again), which calls the fetchServices()
again. This is why it is going in infinite loop.
The solution: You should call your fetchServices()
in componentWillMount/componentDidMount method like this:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { AddServiceContainer } from './AddServiceContainer'
import { ServiceCard } from '../../components'
import { getServices } from '../../actions'
import * as api from '../../services/api'
export class ServicesContainer extends Component {
constructor(props) {
super(props);
this.state = {
services: props.state.servicesReducer.services,
fetchingServices: true,
addingService: false
}
this.fetchServices = this.fetchServices.bind(this);
}
componentWillMount(){
this.fetchServices();
}
onFormSubmit(e, user) {
e.preventDefault();
this.props.searchUser(user)
}
fetchServices() {
console.log('fetchServices')
api.getServices(12345).then(res => {
console.log(' api.getServices res:', res)
this.setState({
fetchingServices: false
});
});
}
render() {
return (
<div className='services-container'>
<ul className='services-list'>
<li>
<AddServiceContainer />
</li>
{ this.state.fetchingServices
? <div className="icon-spin5 animate-spin"></div>
: null }
</ul>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
state
}
}
const mapDispatchToProps = (dispatch) => {
return {
getServices: (services) => { dispatch(getServices(services)) }
}
}
Upvotes: 6
Reputation: 299
You should never fetch data in render function. You should do it in componentDidMount function.
render is called after each state or props change, and if you execute an api call in render function, it will trigger setState and by doing so - render again and again and again...
See link
Upvotes: 6