React中使用Promise的setState导致无限循环

5

预期结果

当调用fetchServices()时,将调用api.getServices并在promise中调用this.setState来将fetchingServices更改为false。这将隐藏加载旋转动画。

结果

由于某些原因,应用程序被卡在无限循环中:

enter image description here

在我的 ServicesContainer 中

constructor(props) {
  super(props);
  this.state = {
    services: props.state.servicesReducer.services,
    fetchingServices: true,
    addingService: false
  }
  this.fetchServices = this.fetchServices.bind(this);
}

The return()

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()

fetchServices() {
  console.log('fetchServices')
  api.getServices(12345).then(res => {
    console.log(' api.getServices res:', res)

    this.setState({
      fetchingServices: false
    });
  });
}

完整代码

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)
2个回答

6
每当你调用setState方法时,render方法都会被再次调用。问题在于你正在render方法中调用fetchServices()方法。现在每当调用fetchServices()方法时,它会调用一个api。当api的结果返回时,你使用setState方法设置状态,这会导致重新渲染(即再次调用render方法),从而再次调用fetchServices()方法。这就是为什么它会进入无限循环的原因。
解决方法:你应该像这样在componentWillMount/componentDidMount方法中调用fetchServices()方法:
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)) }
    }
}

6

在渲染函数中不应获取数据,而应在componentDidMount函数中获取数据。

每次状态或属性更改后都会调用渲染函数,如果在渲染函数中执行api调用,它将触发setState并反复地调用渲染函数...

请参见链接


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接