【问题标题】:In redux-observable - How can I dispatch an action "mid-stream" without returning the value of that action?在 redux-observable 中-如何在不返回该操作的值的情况下分派“中流”操作?
【发布时间】:2018-05-22 17:26:20
【问题描述】:

我到处搜索,找不到以下问题的答案...

在我的 addItemEpic 中,我想在发送 ajax 请求之前调度一个“加载”操作 - 我不希望返回操作的值 - 我只想执行操作然后返回 ajax 响应。 这可以通过 store.dispatch() 轻松实现,如下所示:

export const addItemsEpic = (action$, store) =>
  action$.ofType(ADD_ITEM)
    .do(() => store.dispatch({
        type: 'layout/UPDATE_LAYOUT',
        payload: { loading: true } 
    }))
    .switchMap(action => api.addItem(action.payload))
    .map(item => loadItem(item))
    .do(() => store.dispatch({
       type: 'layout/UPDATE_LAYOUT',
       payload: { loading: false } 
    }))
    .catch(error => Observable.of({
       type: 'AJAX_ERROR',
       payload: error,
       error: true
   }));

但是在 redux-observable 中不推荐使用 store.dispatch()。

我已经尝试使用几乎所有可能的运算符,但我仍然无法在不破坏下一个链接函数中的返回值的情况下调度操作。我认为应该这样做:

action$.ofType(ADD_ITEM)
   .concatMap(action => Observable.of(
      updateLayout({loading: true}),
      api.addItem(action.payload)).last())
   .map(item => loadItem(item))

但不幸的是这里有两个问题:

  • 没有分派加载操作(值作为可观察值返回)
  • api 请求现在返回一个包装好的承诺,而不是一个可映射的值

我非常感谢这里的一些帮助或建议,因为我找不到任何方法来使它正常工作。

提前致谢

【问题讨论】:

    标签: reactjs redux rxjs5 redux-observable


    【解决方案1】:

    第二种形式是在正确的道路上。这个想法是返回一个Observable,它首先发出加载动作,然后在服务调用之后发出loaded 动作或error 动作,最后发出完成加载动作。

    const addItemEpic = action$ => action$
      .ofType(ADD_ITEM)
      .switchMap(action => { // or use mergeMap/concatMap depending on your needs
        const apiCall$ = Observable.fromPromise(api.addItem(action.payload))
          .map(item => actions.loadItem(item))
          .catch(err => Observable.of(actions.ajaxError(err)));
    
        return Observable.concat(
          Observable.of(actions.updateLayout(true)),
          Observable.concat(apiCall$,
            Observable.of(actions.updateLayout(false))));
      });
    

    Observable.fromPromise()Promise 转换为 Observable

    【讨论】:

    • 哈——太棒了!发挥了魅力......谢谢罗伯特。
    【解决方案2】:

    罗伯特的回答很棒,而且是正确的。以下是我的一些额外想法:

    重用现有操作

    当您发现自己同步执行一个又一个动作时,这通常表明您的减速器应该只需要第一个动作。

    例如而不是让layout/UPDATE_LAYOUT 设置loading: true,你的reducer 可以只知道只要有ADD_ITEMLOAD_ITEM 这意味着它应该是loading: true。如果这种隐含性不是你的包,你可以使用额外的元数据作为信号而不是动作类型本身。

    const layoutReducer = (state = { loading: false }, action) => {
      // instead of listening for an action type, we're looking for some other 
      // metadata by convention. In this case the `layout` property.
      if (action.layout) {
        return { ...state, ...action.layout };
      } else {
        return state;
      }
    };
    
    // the schema you use (payload vs layout vs metadata, etc) is your call
    store.dispatch({
      type: 'DOESNT_MATTER',
      payload: 'whatever',
      layout: { loading: true }
    });
    

    话虽如此,您的示例可能已被简化,以便更容易询问 SO(一个好主意)。有时,为了清晰、关注点分离、可重用性或仅仅因为您必须因为您不控制正在侦听它的库而将它们分开操作确实很有意义。例如react-router-redux 你需要调度特殊的动作来做路由转换。

    因此,请将此视为“牢记在心”的建议,而不是教条:)

    连接

    concat 支持任意数量的参数,因此您只需要其中一个:

    const addItemEpic = action$ => action$
      .ofType(ADD_ITEM)
      .switchMap(action => {
        const apiCall$ = Observable.fromPromise(api.addItem(action.payload))
          .map(item => actions.loadItem(item))
          .catch(err => Observable.of(actions.ajaxError(err)));
    
        return Observable.concat(
          Observable.of(actions.updateLayout(true)),
          apiCall$,
          Observable.of(actions.updateLayout(false))
        );
      });
    
    // or 
    
    const addItemEpic = action$ => action$
      .ofType(ADD_ITEM)
      .switchMap(action =>
        Observable.concat(
          Observable.of(actions.updateLayout(true))
          Observable.fromPromise(api.addItem(action.payload))
            .map(item => actions.loadItem(item))
            .catch(err => Observable.of(actions.ajaxError(err))),
          Observable.of(actions.updateLayout(false))
        )
      );
    

    【讨论】:

    • 嗯,是的 - 杰伊是个好主意。我可以让布局减速器监听 ADD_ITEM / LOAD_ITEM。我想我对无法在流中实现我想要的东西(为了知识起见)感到更加沮丧 - 话虽如此 - 能够追溯在给定时间内发生的具体操作以提高透明度可能会很好。 .. 正如你提到的 - “关注点分离”......感谢您的建议:) 是的,我注意到了不必要的连接嵌套。
    猜你喜欢
    • 2016-05-26
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 2021-05-21
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    相关资源
    最近更新 更多