1

我正在制作一个非常简单的 React 组件,它显示从远程源获得的数据。在获取数据之前,它必须等待用户正确登录。这是我尝试这样做的方法:

class MyComponent extends React.Component {
  componentDidUpdate () {
    if (this.props.loggedIn) {
      api.getData()
        .then(() => {
          this.props.dispatch({
            type: 'gotData'
          })
        }, (reason) => {
          this.props.dispatch({
            type: 'getDataFailed'
          })
        })
    }
  }
}

用我自己的话来说,每次与该组件(在本例中为loggedInprop)相关的状态的一部分被更新时,componentDidUpdate都会被调用,如果我看到用户已登录,我就可以获取数据。

这实际上工作得很好,除了一个主要问题:似乎调用dispatch最终会再次触发componentDidUpdate,所以我最终陷入了无限循环。我什至不必在任何地方监听这些调度事件,使用该dispatch函数的简单事实足以componentDidUpdate再次触发。

我的猜测是 dispatch 执行了我内部使用的根 reducer setState,从而再次触发了整个update生命周期链。

这种事情通常是怎么做的?如何dispatch从内部调用componentDidUpdate而不会陷入无限循环?

4

2 回答 2

0

当您收到登录状态时,将您的 api 调用移至操作!像这样的东西:

api.getUserLoggedInStatus().then((status) => {
  dispatch({
    type: 'loggedInStatus',
    status
  });
  api.getData.... // and dispatch
};

此流程将避免任何循环或竞争条件。

于 2017-07-22T23:09:25.357 回答
0

解决此问题的一种简单方法是添加一个附加标志,例如loggingIn,您在异步操作之前设置(通过调度)并在之后重置。您还需要跟踪登录失败的时间,以将此情况与登录过程未启动时区分开来(除非您想在失败时自动重新启动该过程):

class MyComponent extends React.Component {
  componentDidUpdate () {
    const { loggedIn, loggingIn, loginFailed, dispatch } = this.props;
    if (!loggingIn && !loggedIn && ! loginFailed) {
      dispatch({
        type: 'gettingData' // this one sets loggingIn to true, loggedIn to false, loginFailed to false
      });
      api.getData()
        .then(() => {
          dispatch({
            type: 'gotData' // this one sets loggingIn to false, loggedIn to true, loginFailed to false
          })
        }, (reason) => {
          dispatch({
            type: 'getDataFailed' // this one sets loggingIn to false, loggedIn to false, loginFailed to true
          })
        })
    }
  }
}

如果你不想在 redux 中设置这个状态,你也可以让这个控件存在于你的组件本身中:

class MyComponent extends React.Component {
  componentDidUpdate () {
    const { loggedIn, dispatch } = this.props;
    const { loggingIn, loginFailed } = this.state;

    if (!loggingIn && !loggedIn && !loginFailed) {
      this.setState({
        loggingIn: true
      })
      api.getData()
        .then(() => {
          this.setState({
            loggingIn: false,
            loginFailed: false
          });
          dispatch({
            type: 'gotData'
          })
        }, (reason) => {
          this.setState({
            loggingIn: false,
            loginFailed: true
          });
          dispatch({
            type: 'getDataFailed'
          })
        })
    }
  }
}

如果适合您的用户体验,您可以使用该loggingIn标志向您的用户显示微调器,或使用该loginFailed标志显示一条​​消息。

于 2017-07-22T18:51:07.700 回答