gpt4 book ai didi

javascript - componentDidMount 生命周期方法中的条件异步操作不断循环

转载 作者:行者123 更新时间:2023-11-30 11:28:55 28 4
gpt4 key购买 nike

我正在使用连接到 API 的 redux 和 sagas 开发一个 React 应用。

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

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

现在,我正在尝试使用一项附加功能,当从程序的配置文件页面访问此表单时,该功能会使用 programId 自动填充表单。在这种情况下,由于 programId 甚至在组件安装之前就已预加载到 formData 中,因此不会触发 componentWillReceiveProps,因为 prop 没有变化。所以我决定在 componentDidMount 生命周期方法中获取 programContacts,如下所示:-

componentDidMount() {
if (this.props.programId !== '' && !this.props.programContactData.length) {
this.props.fetchProgramContacts(this.props.programId);
}
}

逻辑是只有当programId不为空且programContacts为空时,才必须进行fetch请求。但这会无限循环获取。

我发现 if 语句被反复执行,因为 if 语句主体中的表达式甚至在前一个获取请求返回结果之前就被 componentDidMount 再次执行。并且因为其中一个条件是检查结果数组的长度是否为非空,所以 if 语句返回 true,因此循环继续进行,而不会让先前的请求完成。

我不明白的是为什么if语句必须重复执行。难道if语句执行一次就退出生命周期方法吗?

我知道也许可以使用某种超时方法来让它工作,但这不是我可以依赖的足够强大的技术。

是否有实现此目的的最佳实践?

此外,是否有任何建议不要在 componentDidMount 方法中使用 if 条件?

最佳答案

在 React 生命周期中,componentDidMount() 只会被触发一次。

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

如果调用确实来自 componentDidMount,则意味着您的组件每次都会重新创建。可以通过在组件的 constructor 中添加 console.log 来检查它。

无论如何,您应该更喜欢使用 redux 的 isFetchingdidInvalidate 来处理数据获取/重新获取。

您可以在另一个问题中看到我对其工作原理的详细回答之一:React-Redux state in the component differs from the state in the store


如果我专注于您的用例,您可以在下面看到 isFetchingdidInvalidate 概念的应用。

<强>1。组件

看看 Action 和缩减器,但 redux 的技巧是使用 isFetchingdidInvalidate Prop 。

当您想要获取数据时,唯一的两个问题是:

  1. 我的数据是否仍然有效?
  2. 我目前正在获取数据吗?

您可以在下面看到,每当您选择一个程序时,您都会使获取的数据,以便使用新的 programId 作为过滤器再次获取。

注意:当然,您应该使用 reduxconnect 将操作和 reducer 传递给您的组件!

主视图.js

class MainView extends React.Component {
return (
<div>
<ProgramDropdown />
<ContactDropdown />
</div>
);
}

ProgramDropdown.js

class ProgramDropdown extends React.Component {
componentDidMount() {
if (this.props.programs.didInvalidate && !this.props.programs.isFetching) {
this.props.actions.readPrograms();
}
}

render() {
const {
isFetching,
didInvalidate,
data,
} = this.props;

if (isFetching || (didInvalidate && !isFetching)) {
return <select />
}

return (
<select>
{data.map(entry => (
<option onClick={() => this.props.actions.setProgram(entry.id)}>
{entry.value}
</option>
))}
</select>
);
}
}

ContactDropdown.js

class ContactDropdown extends React.Component {
componentDidMount() {
if (this.props.programs.selectedProgram &&
this.props.contacts.didInvalidate && !this.props.contacts.isFetching) {
this.props.actions.readContacts(this.props.programs.selectedProgram);
}
}

componentWillReceiveProps(nextProps) {
if (nextProps.programs.selectedProgram &&
nextProps.contacts.didInvalidate && !nextProps.contacts.isFetching) {
nextProps.actions.readContacts(nextProps.programs.selectedProgram);
}
}

render() {
const {
isFetching,
didInvalidate,
data,
} = this.props;

if (isFetching || (didInvalidate && !isFetching)) {
return <select />
}

return (
<select>
{data.map(entry => (
<option onClick={() => this.props.actions.setContact(entry.id)}>
{entry.value}
</option>
))}
</select>
);
}
}

<强>2。联系人操作

我将只关注接触操作,因为程序几乎相同。

export function readContacts(programId) {
return (dispatch, state) => {
dispatch({ type: 'READ_CONTACTS' });

fetch({ }) // Insert programId in your parameter
.then((response) => dispatch(setContacts(response.data)))
.catch((error) => dispatch(addContactError(error)));
};
}

export function selectContact(id) {
return {
type: 'SELECT_CONTACT',
id,
};
}

export function setContacts(data) {
return {
type: 'SET_CONTACTS',
data,
};
}

export function addContactError(error) {
return {
type: 'ADD_CONTACT_ERROR',
error,
};
}

<强>3。联系 reducer

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;
}
}

希望对您有所帮助。

关于javascript - componentDidMount 生命周期方法中的条件异步操作不断循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46974280/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com