【问题标题】:React setState in promise causing infinite loop在承诺中反应 setState 导致无限循环
【发布时间】:2018-01-03 15:59:35
【问题描述】:

预期

fetchServices()被调用时,api.getServices被调用并且在promise中this.setState被调用来改变fetchingServicesfalse。然后隐藏加载微调器动画。

结果

由于某种原因,应用程序陷入了无限循环:

在我的 ServicesContainer 中

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

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)

【问题讨论】:

    标签: javascript reactjs promise


    【解决方案1】:

    每当您执行 setState 时,都会再次调用 render 方法。现在这里的问题是你在渲染方法中调用fetchServices() 方法。现在,每当调用 fetchServices() 时,它都会调用一个 api。当 api 的结果到来时,您正在使用setState 设置状态,这会导致重新渲染(即再次调用您的渲染方法),这会再次调用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)) }
        }
    }
    

    【讨论】:

      【解决方案2】:

      你不应该在渲染函数中获取数据。您应该在 componentDidMount 函数中执行此操作。

      render 在每个 state 或 props 改变后被调用,如果你在 render 函数中执行一个 api 调用,它会触发 setState 并且这样做 - 一次又一次地渲染......

      link

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 2021-04-10
        • 2020-03-25
        • 1970-01-01
        相关资源
        最近更新 更多