Javascript componentDidMount生命周期方法中的条件异步操作继续循环

Javascript componentDidMount生命周期方法中的条件异步操作继续循环,javascript,reactjs,redux,redux-saga,react-lifecycle,Javascript,Reactjs,Redux,Redux Saga,React Lifecycle,我正在使用连接到API的redux和sagas开发react应用程序 有一个表单组件,它有两个下拉字段:一个程序和一个联系人字段。表单的设计工作方式是,当用户选择一个程序时,表单使用programId获取为该程序注册的所有联系人。然后将这些联系人填充为联系人下拉字段的选项。这是可行的,我使用组件WillReceiveProps实现了它,如下所示:- componentWillReceiveProps(nextProps) { if (nextProps.programId !== thi

我正在使用连接到API的redux和sagas开发react应用程序

有一个表单组件,它有两个下拉字段:一个程序和一个联系人字段。表单的设计工作方式是,当用户选择一个程序时,表单使用programId获取为该程序注册的所有联系人。然后将这些联系人填充为联系人下拉字段的选项。这是可行的,我使用组件WillReceiveProps实现了它,如下所示:-

componentWillReceiveProps(nextProps) {
    if (nextProps.programId !== this.props.programId) {
        this.props.fetchProgramContacts(nextProps.programId);
    }
}
componentDidMount() {
    if (this.props.programId !== '' && !this.props.programContactData.length) {
        this.props.fetchProgramContacts(this.props.programId);
    }
}
现在,我正在尝试一个附加功能,当从程序的配置文件页面访问表单时,使用programId自动填充表单。在这种情况下,由于即使在组件装载之前,程序ID也被预加载到formData中,组件WillReceiveProps不会触发,因为道具中没有任何更改。因此,我决定让programContacts在componentDidMount生命周期方法中获取,如下所示:-

componentWillReceiveProps(nextProps) {
    if (nextProps.programId !== this.props.programId) {
        this.props.fetchProgramContacts(nextProps.programId);
    }
}
componentDidMount() {
    if (this.props.programId !== '' && !this.props.programContactData.length) {
        this.props.fetchProgramContacts(this.props.programId);
    }
}
逻辑是,只有当programId不为空且programContacts为空时,才能发出fetch请求。但这是一个无止境的获取循环

我发现if语句会一次又一次地执行,因为即使在返回前一个fetch请求和结果之前,if语句体中的表达式也会被componentDidMount再次执行。由于其中一个条件是检查结果数组的长度是否为非空,因此if语句返回true,因此循环继续进行,而不让前面的请求完成

我不明白的是为什么if语句必须重复执行。if语句执行一次后,它不应该退出生命周期方法吗

我知道也许可以使用某种超时方法来实现这一点,但这对我来说还不够可靠

是否有实现这一目标的最佳实践


另外,有没有建议不要在componentDidMount方法中使用if条件?

实际问题在于componentWillReceiveProps方法本身,这里创建了无限循环。 您正在检查当前和下一个programId是否不匹配,然后触发一个操作,使当前和下一个programId再次不匹配。对于给定的操作fetchProgramContacts,您正在以某种方式改变程序ID。检查减速器

其中一个解决方案是在减速器中添加reqFinished(真/假),然后您应该执行以下操作:

componentWillReceiveProps(nextProps){
  if(nextProps.reqFinished){
    this.props.fetchProgramContacts(nextProps.programId);
  }
}

在React生命周期中,
componentDidMount()
仅触发一次

确保调用是从
componentDidMount
进行的,而不是
componentWillReceiveProps

如果调用真正来自
componentDidMount
,则表示每次都会重新创建组件。 可以通过在组件的
构造函数中添加
控制台.log
来检查它

在任何情况下,您都应该使用redux的
isFetching
didvalidate
来处理数据获取/重新提取

您可以在另一个问题中看到我对其工作原理的详细回答:


如果我关注您的用例,您可以在下面看到
isFetching
didvalidate
概念的应用程序。

1。组件

import { combineReducers } from 'redux';

export default combineReducers({
  didInvalidate,
  isFetching,
  data,
  selectedItem,
  errors,
});

function didInvalidate(state = true, action) {
  switch (action.type) {
    case 'SET_PROGRAM': // !!! THIS IS THE TRICK WHEN YOU SELECT ANOTHER PROGRAM, YOU INVALIDATE THE FETCHED DATA !!!
    case 'INVALIDATE_CONTACT':
        return true;
    case 'SET_CONTACTS':
      return false;
    default:
      return state;
  }
}

function isFetching(state = false, action) {
  switch (action.type) {
    case 'READ_CONTACTS':
      return true;
    case 'SET_CONTACTS':
      return false;
    default:
      return state;
  }
}

function data(state = {}, action) {
  switch (action.type) {
    case 'SET_CONTACTS': 
      return action.data;
    default:
      return state;
  }
}

function selectedItem(state = null, action) {
  switch (action.type) {
    case 'SELECT_CONTACT': 
      return action.id;
    case 'READ_CONTACTS': 
    case 'SET_CONTACTS': 
      return null;
    default:
      return state;
  }
}

function errors(state = [], action) {
  switch (action.type) {
    case 'ADD_CONTACT_ERROR':
      return [
        ...state,
        action.error,
      ];
    case 'SET_CONTACTS':
      return state.length > 0 ? [] : state;
    default:
      return state;
  }
}
看看操作和减缩器,但是redux的技巧是使用
isFetching
didvalidate
道具

当您想要获取数据时,只有两个问题:

  • 我的数据仍然有效吗
  • 我当前正在获取数据吗
  • 您可以在下面看到,每当您选择一个程序时,您将使所获取的数据无效,以便使用新的programId作为过滤器再次获取

    注意:当然,您应该使用
    redux
    connect
    将操作和减速器传递给您的组件

    MainView.js

    class MainView extends React.Component {
      return (
        <div>
          <ProgramDropdown />
          <ContactDropdown />
        </div>
      );
    }
    
    3。触点减速器

    import { combineReducers } from 'redux';
    
    export default combineReducers({
      didInvalidate,
      isFetching,
      data,
      selectedItem,
      errors,
    });
    
    function didInvalidate(state = true, action) {
      switch (action.type) {
        case 'SET_PROGRAM': // !!! THIS IS THE TRICK WHEN YOU SELECT ANOTHER PROGRAM, YOU INVALIDATE THE FETCHED DATA !!!
        case 'INVALIDATE_CONTACT':
            return true;
        case 'SET_CONTACTS':
          return false;
        default:
          return state;
      }
    }
    
    function isFetching(state = false, action) {
      switch (action.type) {
        case 'READ_CONTACTS':
          return true;
        case 'SET_CONTACTS':
          return false;
        default:
          return state;
      }
    }
    
    function data(state = {}, action) {
      switch (action.type) {
        case 'SET_CONTACTS': 
          return action.data;
        default:
          return state;
      }
    }
    
    function selectedItem(state = null, action) {
      switch (action.type) {
        case 'SELECT_CONTACT': 
          return action.id;
        case 'READ_CONTACTS': 
        case 'SET_CONTACTS': 
          return null;
        default:
          return state;
      }
    }
    
    function errors(state = [], action) {
      switch (action.type) {
        case 'ADD_CONTACT_ERROR':
          return [
            ...state,
            action.error,
          ];
        case 'SET_CONTACTS':
          return state.length > 0 ? [] : state;
        default:
          return state;
      }
    }
    

    希望有帮助。

    您确定它是从
    componentDidMount()
    调用的吗?如果在
    componentDidMount()
    的顶部随机记录一些内容,会发生什么情况?它打印不止一次吗?是的,我在if语句中记录了“this.props.programId和this.props.programContactData.length”,并且在循环中不断得到例如“66和0”。好的,所以问题可能是您的组件不断地重新装载自己。这就解释了这一点,那么我如何克服它呢?我不明白为什么它必须首先重新安装。当我删除if语句时,它不会这样做,这就是为什么我想知道CDM中的条件语句是否是一个问题。哦?因此,如果您添加
    if
    语句,您将得到循环,但不是没有循环?帮个忙,在
    组件didmount()
    if
    之间执行
    console.log(“foo”)
    。然后在
    if
    中的
    console.log(“bar”)
    。记录了多少个
    foo
    和多少个
    bar
    ?感谢@yuantonito花费时间和精力撰写如此详细的答案。我正在读你的答案,突然间,我发现了问题所在。问题在于我试图访问表单的程序中没有注册联系人!!!因此,抓取确实发生了,并且在redux中更新了programContacts。但我使用的条件并没有准备好处理那个案子。并且表单在一个有0多个联系人的程序中按预期工作。现在我知道问题是什么了,我可以找到解决方案了。我选择这个作为答案,因为它提供了在我这样的案例中正确使用方法的见解。不,不是这个。