【问题标题】:ReactJS + Redux: How to wait until dispatch has been completed before moving onto next step?ReactJS + Redux:如何等到调度完成后再进行下一步?
【发布时间】:2017-02-21 18:44:48
【问题描述】:

在 ReactJS + Redux 项目中,我有一个方法可以发出 API 请求。如果成功,我想分派另一个动作创建者并等待它完成。然后当它完成时,进入下一步。

目前,下面的代码在进行另一个 API 调用时执行调度,但即使在通过调度更新状态之前,它也会立即执行window.location.href ='http://localhost:3005/#/Home',然后调度完成。

那么我如何才能等到dispatch(actions.updateUserInfo(userInfo.username)) 完成后再执行下一行代码window.location.href ='http://localhost:3005/#/Home'

这里是动作创建者:

  loggingIn(userInfo) {

    var userInfoBody = {
        'username': `${userInfo.username}`,
        'password': `${userInfo.password}`
    }

    var configuration = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(userInfoBody)
    }

    return function(dispatch) {
      fetch('https://backendserver.com:8080/creds', configuration)
      .then(response => response.json())
      .then(response => {
        //Would like to finish this dispatch completely before start executing window.location.href ='http://localhost:3005/#/Home'
        dispatch(actions.updateUserInfo(userInfo.username))
        window.location.href ='http://localhost:3005/#/Home'
      })
      .catch((error) => {
        console.log("Error: ", error)
      })
    }

提前谢谢你

【问题讨论】:

标签: javascript reactjs redux react-jsx react-redux


【解决方案1】:

使用 react-query,它有更多的功能来获取数据并支持您的需求

【讨论】:

    【解决方案2】:

    如果您从 thunk 中返回 fetch 承诺,那么您可以继续来自调用者的承诺链。假设 updateUserInfo 返回 fetch 承诺,修改了您的代码:

    return function(dispatch) {
      return fetch('https://backendserver.com:8080/creds', configuration)
      .then(response => response.json())
      .then(response => {
        //Would like to finish this dispatch completely before start executing window.location.href ='http://localhost:3005/#/Home'
        dispatch(actions.updateUserInfo(userInfo.username))
         .then(() => {
           window.location.href ='http://localhost:3005/#/Home'
         })
      })
      .catch((error) => {
        console.log("Error: ", error)
      })
    }
    

    但我会将对第二个 thunk (updateUserInfo) 的调用移到 React 组件中,因为第一个 thunk (loggingIn) 做的 imo 太多了。单一责任主体等等。

    【讨论】:

      【解决方案3】:

      将您的window.location.href ='http://localhost:3005/#/Home' 放入您的订阅处理程序中。并确保您订阅了该活动:

      constructor(props, children)
      {
          TheStore.subscribe( this.listenForDispatch.bind( this ) );
      }
      
      listenForDispatch()
      {
          //Check the state is what you want
          if ( TheStore.getState().someProp == "somevalue" )
          {
              //Call it here!
              window.location.href ='http://localhost:3005/#/Home'
          }
      }
      

      编辑:在您开始在代码中使用 Redux 之前,您需要阅读 their documentation and tutorialsubscribe 是 Redux 的基本使用方式之一。

      【讨论】:

      • 对不起,你能用我在原始帖子中提供的代码展示一个例子吗?我似乎不太明白 subscribe 做了什么以及在哪里实现它。
      • @LyManeug 请看我的编辑。如果你不明白 subscribe 在 Redux 中的作用,让我完全编写你的代码对你没有帮助。 (我上面写的代码完全实现了你想要的,如果你懂redux的话)请先阅读文档。
      • 这并不能回答问题,它与在componentWillReceiveProps 中检查 Redux 道具的效果相同。该操作没有说actions.updateUserInfo 会设置任何可用于确定updateUserInfo 是否已完成的状态。
      【解决方案4】:

      一种不需要手动订阅商店并且不需要任何中间件(如其他答案所建议)的方法可以如下:

      减速机:

      function userReducer (state={ doneUpdating: false, userData: null }, action) {
        if (action.type === 'UPDATE_USER_INFO') { // this is the action dispatched by updateUserInfo
          return {  ...state, userData: action.payload, doneUpdating: true }
        }
      }
      

      组件:

      class YourComponent {
        componentWillReceiveProps (nextProps) {
          if (!this.props.doneUpdating && nextProps.doneUpdating) {
            window.location.href ='http://localhost:3005/#/Home'
          }
        }
      
        // Rest of your component methods here...
      }
      
      function mapStateToProps (state) {
        return { doneUpdating: state.userReducer.doneUpdating }
      }
      
      connect(mapStateToProps)(YourComponent)
      

      基本上,在完成状态更新后,您会设置一个标志。您的组件(与 Redux 连接)从状态中读取该标志,并在 componentWillReceiveProps 中检测到更改并做出相应的反应(双关语:))。根据您的情况,您可能需要在componentWillMount 中执行相同的检查/重定向逻辑。如果您需要在尚未安装组件时调度用户更新操作,则需要这样做。在这种情况下,doneUpdating 标志可以在组件被挂载之前变为真,并且不会调用 componentWillReceiveProps。

      【讨论】:

        【解决方案5】:

        执行此操作的最简化的方法可能是引入另一个操作,您将通过执行 window.location.href = '...' 的东西来对此做出反应。

        由于 redux 可以被视为“单线程”,因此您可以确保在每次调用调度您的状态树之间完全更新。

        dispatch(actions.updateUserInfo(userInfo.username))
        // It's guaranteed that at this point your updateUserInfo action is handled and state tree is updated
        dispatch(actions.userInfoUpdated(userInfo.username))
        

        新操作“userInfoUpdated”,然后您将通过执行 window.location.href = '...' 在 redux 中间件中进行处理。

        【讨论】:

        • 对不起,但在我接受答案并投票之前,您能否展示一个示例以及原始帖子中提供的代码以进行澄清?似乎这是最佳做法。
        • 这不是redux方式。 redux 方式是订阅商店并让您的订阅侦听器执行window.location.href
        • @DonRhummy 为什么不是 redux 方式?我觉得还可以
        • @niba 他错过了subscribe 部分。当您调度时,您是在告诉商店发生了一个事件。然后它告诉每个听的人。这是一种非常简洁(并且建议使用 redux)的方式来处理仅在特定操作完成时运行一些代码。
        • @WTK - 我认为 actions.updateUserInfo(userInfo.username) 是一个异步 thunk,所以它不会是完整的。此外,使用中间件拦截动作调度对我来说似乎不是很透明。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-31
        • 2021-03-05
        • 1970-01-01
        • 1970-01-01
        • 2018-08-30
        • 1970-01-01
        • 2021-11-12
        相关资源
        最近更新 更多