我应该在哪里将同步副作用与redux中的操作相关联?

gmr*_*gmr 7 javascript redux

(注意:我的问题没有写清楚,而且我正在考虑一些错误.当前版本的问题只是尝试编写一些可以使被接受的答案对尽可能多的人有用的东西.)

我想要一个动作,将一个项目添加到商店并使用外部依赖项注册它.

我可以使用thunk中间件并编写

export function addItem(item) {
  return dispatch => {
    dispatch(_addItemWithoutRegisteringIt(item));
    externalDependency.register(item);
  };
}
Run Code Online (Sandbox Code Playgroud)

但是在注册项目之前会通知订阅者,他们可能依赖于注册.

我可以改变订单并写

export function addItem(item) {
  return dispatch => {
    externalDependency.register(item);
    dispatch(_addItemWithoutRegisteringIt(item));
  };
}
Run Code Online (Sandbox Code Playgroud)

但是我通过一个唯一的id来跟踪外部依赖项中的项目,它只能在reducer中分配.

我可以在减速器中注册该项目,但我明白在减速器中进行副作用是非常糟糕的形式,并可能导致问题.

那么最好的方法是什么?

(我的结论是:有许多方法可行,但对我的用例来说最好的方法是将句柄存储到Redux中的外部依赖项中,而不是外部依赖项中的Redux句柄.)

Dan*_*mov 10

如果您使用Redux Thunk中间件,则可以将其封装在动作创建器中:

function addItem(id) {
  return { type: 'ADD_ITEM', id };
}

function showNotification(text) {
  return { type: 'SHOW_NOTIFICATION', text };
}

export function addItemWithNotification(id) {
  return dispatch => {
    dispatch(addItem(id));
    doSomeSideEffect();
    dispatch(showNotification('Item was added.');
  };
}
Run Code Online (Sandbox Code Playgroud)

根据对此答案的评论进行阐述:

那么也许这是我案例的错误模式.我不希望在dispatch(addItem(id))和之间调用订阅者doSomeSideEffect().

在95%的情况下,您不应该担心订阅者是否被调用.如果数据没有改变,React Redux之类的绑定将不会重新呈现.

doSomeSideEffect()减速器放入可接受的方法还是有隐藏的陷阱?

不,将副作用放入减速机是绝对不可接受的.这违背了Redux的核心前提,并打破了其生态系统中的任何工具:Redux DevTools,Redux Undo,任何记录/重放解决方案,测试等.绝不要这样做.

如果你真的需要与动作一起执行副作用,并且你真的关心只有被通知一次的订阅者,只需发出一个动作并使用[Redux Thunk]"附加"副作用:

function addItem(id, item) {
  return { type: 'ADD_ITEM', id, item };
}

export function addItemWithSomeSideEffect(id) {
  return dispatch => {
    let item = doSomeSideEffect(); // note: you can use return value
    dispatch(addItem(id, item));
  };
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您需要处理ADD_ITEM不同的减速器.没有两次通知订户就不需要发送两个动作.

这是我仍然无法理解的一点.Dan建议thunk中间件不能推迟订阅者通知,因为这会破坏异步请求的常见用例.我仍然不明白这一点.

考虑一下:

export function doSomethinAsync() {
  return dispatch => {
    dispatch({ type: 'A' });
    dispatch({ type: 'B' });
    setTimeout(() => {
      dispatch({ type: 'C' });
      dispatch({ type: 'D' });
    }, 1000);
  };
}
Run Code Online (Sandbox Code Playgroud)

您希望何时通知订阅?当然,如果我们仅在thunk退出时通知订户,我们将不会通知他们CD.

无论哪种方式,使用当前的中间件架构都是不可能的.中间件并不意味着阻止用户解雇.

但是,您所描述的内容可以使用诸如redux-batched-subscribe之类的商店增强程序来完成.它与Redux Thunk无关,但它会导致同步调度的任何一组动作被去抖.通过这种方式,您可以获得一个AB,以及另一个通知CD.在我看来,依赖于这种行为编写代码会很脆弱.