【问题标题】:How to dispatch two actions in one epic, which could be in the same or in another reducer如何在一个史诗中分派两个动作,这两个动作可以在同一个或另一个减速器中
【发布时间】:2023-01-20 18:44:47
【问题描述】:

我有两只鸭子(ui 和后端),里面有史诗。 完成后端操作后,我需要触发两个动作 其中一个动作位于后端鸭子中,另一个位于 ui 鸭子中。

我从后台操作开始,一切都按预期进行。 添加第二个操作会导致我遇到问题,因为我可以访问操作(控制台正确记录),但不能访问 reducer(无日志)

我要解决的挑战是:

  • 在一个史诗中开始两个动作
  • 在另一个减速器中调度一个动作

我的代码看起来与此类似:

backendDuck 的史诗:

fetchFooEpic : (action$, store) =>
  action$.pipe(
    operators.filter(action => action.type === types.LOAD),
    
    // start added section for second call
    operators.switchMap(action => {
      const response = operators.from(fetchSomeUrl(action))
      .pipe(
          operators.of(uiDuck.actions.fetchUserFulfilled(response.props)),
      ),
      operators.catchError(err => {
        console.error('Error happened!', err.message)
        return rxjs.of({ type: types.ADD_CATEGORY_ERROR, payload: err })
      })
      
      return response
    }),
    // start added section for second call

    // original first call
    operators.map(a => ({ type: types.ENDACTION,  payload: a.payload })),

    operators.catchError(err => {
      console.error('Error happened!', err.message)
      return rxjs.of({ type: types.ADD_CATEGORY_ERROR, payload: err })
    })
  )

uiDuck:

export actions={
...
fetchUserFulfilled: (value) => {
  console.log('hello from action')
  return ({ type: types.FETCHUSERFULFILLED, payload: value })
},
...
}

...
export default function reducer(state = initialState, action) {
  switch (action.type) {
    case types.FETCHUSERFULFILLED:
      console.log('hello from reducer')
      return {
        ...state,
        user: action.payload,
      }
    ...
  

【问题讨论】:

    标签: redux-observable


    【解决方案1】:

    原来我以错误的方式组合了这两个调用。 为了能够进行管道传输,管道传输的 observable 需要再次返回一个 observable。
    当映射到另一个 redux-action 时,在我看来它不会返回可观察的(?)因此,需要在同一位置对所有所需的 redux-actions 进行调用(例如使用 concat)

    为了完整起见,我努力在 cmets 中解释代码的所有部分

    
    fetchFooEpic : (action$, store) =>
    action$.pipe(
      operators.filter(action => action.type === types.LOAD),                       // Filter
      operators.switchMap(action =>                                                 // restart inner actions on each call
        operators.from(fetchSomeUrl(action))                                            // creating observable from result
        .pipe(                                                                      // starting new flow on observable (self)
          //operators.tap(a => console.log('Now running fetchfooepic 2', a)),       // dedicated location for sideeffects
          operators.switchMap(                                                      // restart inner actions on each call
            (response) => operators.concat(                                         // Kicking off several actions sequentially (merge() would do that in parallel)
            operators.of(uiDuck.actions.fetchUserFulfilled(response)),                   // addressing the redux action in other reducer
            operators.of(({                                                         // addressing the redux action via the type in this duck (ENDACTION is controlled by epics only, no action exists for it)
              type: types.ENDACTION,  
              payload: response
            }})),
          )),
          operators.catchError(err =>{
            console.error('Shit happens!', err.message)                             // errorhandling
            return rxjs.of({ type: types.ADD_CATEGORY_ERROR, payload: err })
          })
        )
      )
    ),
    

    通常,这些函数在文档中包含一些(或多或少可以理解的)示例 https://rxjs.dev/api/index/function/

    【讨论】:

      猜你喜欢
      • 2020-07-29
      • 2021-01-13
      • 2018-04-18
      • 1970-01-01
      • 2018-12-13
      • 2021-06-05
      • 2016-08-12
      • 2018-03-18
      • 1970-01-01
      相关资源
      最近更新 更多