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

标签 javascript reactjs redux redux-saga react-lifecycle

我正在使用连接到 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/

相关文章:

javascript - Rickshaw:如何设置x轴和y轴的颜色?

javascript - flex 盒元素无法在 Chrome 上正确重新呈现

javascript - 谷歌的 "Beat the boot"

Javascript 获取数据类型标签值

javascript - React Hook 的 componentWillReceiveProps、componentDidUpdate

android - 在 React Native 中加载屏幕时如何滚动到顶部?

javascript - reactjs - 在悬停时为从数组呈现的列表项呈现单个图标

javascript - Redux mapStateToProps 属性依赖

javascript - 在组件外部(外部模块即 webSocket)使用存储函数(dispatch、getState、)

reactjs - react-router-dom 链接在 app.js(父组件)中工作,但在子组件中不起作用