Redux Thunk 同步动作不同步

Posted

技术标签:

【中文标题】Redux Thunk 同步动作不同步【英文标题】:Redux Thunk synchronous actions are not synchronous 【发布时间】:2019-02-03 04:57:47 【问题描述】:

我正在为我正在构建的应用程序使用 React/Redux,并且我正在尝试实施一个操作来注销用户。我的应用程序具有可以编辑的工件。我希望我的应用程序首先保存工件,然后注销用户,这将清除商店。我使用 Redux Thunk 实现了如下:

export function logoutUser(artifact) 
  return (dispatch) => 
    dispatch(saveArtifact(artifact))
      .then(() => 
        dispatch(requestLogout());
        return axios.get(`$API_BASE/auth/logout`)
          .then(() => dispatch(logoutSuccess()))
          .catch(error => dispatch(logoutFailure(error)));
      );
  ;

我希望这可以保存工件,并且只有在保存后,才将用户注销。我的保存操作本身调用另一个操作,它在保存工件后加载工件,但这无关紧要。它应该返回一个承诺,然后才继续注销用户。

但是,事实并非如此。出于某种原因,我收到多个调用来保存工件(验证它们来自此函数),然后调用异步发生,因此加载工件是最后一次,因此我的 redux 存储在注销时不会被清除。

如果有人能提供一些关于为什么会发生这种情况以及我如何解决它的见解,我会很高兴。

附加信息:

我正在清除我的 root reducer 中的 redux 存储,如下所示:

const rootReducer = (state, action) => 
  let newState = state;
  if (action.type === types.LOGOUT_SUCCESS) 
    newState = undefined;
  

  return appReducer(newState, action);
;

我将工件保存如下:

function sendSaveArtifactRequest(artifact) 
  if (artifact._id == null) 
    const artifactWithoutId = _.omit(artifact, ['_id']);
    return axios.post(`$API_BASE/artifacts`, artifactWithoutId)
      .then(result => result.data);
  

  return axios.put(`$API_BASE/artifacts`, artifact).then(() => artifact);


export function saveArtifact(artifact) 
  return (dispatch) => 
    dispatch(requestSaveArtifact());

    return sendSaveArtifactRequest(artifact)
      .then(data => dispatch(saveArtifactSuccess(data)))
      .catch(error => dispatch(saveArtifactFailure(error)))
      .then(() => dispatch(loadArtifacts()));
  ;

我正在按如下方式加载工件:

function sendArtifactsRequest() 
  return new Promise((resolve, reject) => 
    axios.get(`$API_BASE/artifacts`)
      .then(result => resolve(result.data))
      .catch(error => reject(error));
  );


export function loadArtifacts() 
  return (dispatch) => 
    dispatch(requestArtifacts());

    return sendArtifactsRequest()
      .then(data => dispatch(loadArtifactsSuccess(data)))
      .catch(error => dispatch(loadArtifactsFailure(error)));
  ;

【问题讨论】:

你是如何清理 redux store 的? 将该信息添加到我的帖子中,该帖子基于此帖子:netbasal.com/… 你在哪里调度清除 redux 状态动作? 没有 redux 操作。如果您查看我发布的链接,它会解释正在发生的事情。在我的例子中,root reducer 会查看 LOGOUT_SUCCESS 操作是否通过,如果是,则重置状态。 你能提供saveArtifact的代码吗? 【参考方案1】:

我发现了问题,您的 saveArtifact 操作中有多个链式承诺。在您的情况下发生了什么,在 sendSaveArtifactRequest 承诺解决之后您发送 requestLogout 并在成功后您清除 redux 状态。但另一方面,仍有待处理的承诺,您无需等待logoutUser 行动中的解决方案。当您清除 redux 存储时,您未决的承诺将得到解决,并再次更新 redux 状态。 你可以在这里做两件事:

在调度 saveArtifact 时使用 Promise.all().then(),然后调度注销操作。 您可以在loadArtifacts 操作中注销用户,但我不确定具体的用例,可能这不符合您的应用要求。但它总是会在加载工件时调用。

最重要的是,请将 Redux DevTools 集成到您的应用中,以便您可以跟踪调度操作的顺序。

在你的store.js

import  createStore, compose, applyMiddleware  from 'redux';
import thunk from 'redux-thunk';

import rootReducer from './reducers';

const enhancer = compose(
  applyMiddleware(thunk),
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
);

export default createStore(rootReducer, enhancer);

`

【讨论】:

感谢您的建议。不幸的是,我无法将注销链接到保存或加载工件,因为我在其他地方使用它们。关于使用Promise.all(),这也无济于事,因为我不会返回一个以上的承诺。我将承诺链接如下:saveArtifact > loadArtifacts > logoutUser,在调用 .then() 之前一次只返回一个承诺。这真的是我的问题。为什么他们没有被正确链接?为什么saveArtifact 会被多次调用?

以上是关于Redux Thunk 同步动作不同步的主要内容,如果未能解决你的问题,请参考以下文章

带有 Typescript 的 Redux Thunk

在 redux 中在哪里调度多个操作?

异步action和redux-thunk理解

React-Redux-Thunk:动作不返回调度

Redux-Thunk - 异步动作创建者承诺和链接不起作用

redux-thunk的理解