Javascript componentDidMount生命周期方法中的条件异步操作继续循环
我正在使用连接到API的redux和sagas开发react应用程序 有一个表单组件,它有两个下拉字段:一个程序和一个联系人字段。表单的设计工作方式是,当用户选择一个程序时,表单使用programId获取为该程序注册的所有联系人。然后将这些联系人填充为联系人下拉字段的选项。这是可行的,我使用组件WillReceiveProps实现了它,如下所示:-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
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多个联系人的程序中按预期工作。现在我知道问题是什么了,我可以找到解决方案了。我选择这个作为答案,因为它提供了在我这样的案例中正确使用方法的见解。不,不是这个。