从redux-observable epic

时间:2018-03-09 08:48:55

标签: typescript redux rxjs rxjs5 redux-observable

简而言之,我想设置一个执行请求的epic,并根据正在履行或拒绝的请求发送一个动作。然后,我希望史诗可以根据结果和当前状态发出额外的动作。

第一部分是直截了当的

const fetchFooEpic: Epic<ActionAny, RootState> = (action$, store) =>
  action$.pipe(
    ofType<ActionAny, ReturnType<typeof actions.foo.fetch>>(actions.foo.types.FETCH_ALL),
    switchMap(action =>
      ajax({
        method: 'GET',
        url: `${path}/foo/${action.payload}`,
        headers: { Authorization: store.getState().user.token }
      }).pipe(
        map(({response}) => actions.foo.fetchFulfilled(response)),
        catchError(error => of(actions.foo.fetchRejected(error)))
      )
    )
  )

但是我在引入另一个动作时遇到了麻烦,或者在混合中空洞。我想想我想使用mergeMap并在没有任何东西被调度时清空,但我得到了类型错误。

const fetchMissingRelations = (response: Foo[], state: RootState) => {
  const unknown: BarId[] = foo
    .map(foo => foo.barId)
    .filter(barId => !state.bar.entities[barId])
  return unknown.length
    ? actions.bar.fetch([...new Set(unknown)])
    : empty<never>()
}

const fetchFooEpic: Epic<ActionAny, RootState> = (action$, store) =>
  action$.pipe(
    ofType<ActionAny, ReturnType<typeof actions.foo.fetch>>(actions.foo.types.FETCH_ALL),
    switchMap(action =>
      ajax({
        method: 'GET',
        url: `${path}/foo/${action.payload}`,
        headers: { Authorization: store.getState().user.token }
      }).pipe(
        mergeMap(({response}) => of(
          actions.foo.fetchFulfilled(response),
          fetchMissingRelations(response, store.getState())
          // err: property 'type' is missing in {}
        )),
        catchError(error => of(actions.foo.fetchRejected(error)))
      )
    )
  )

我最终进入了https://github.com/redux-observable/redux-observable/issues/339,但为我提供了明确的永不输入,并为我工作。

这是一个问题(随意停在这里),但是这里有一些额外的背景,为什么我要尝试这样做,如果有人可以建议替代方案,我会很感激的方法:

我有一些关系数据的状态切片,这些切片都来自不同API端点的网络。在这种情况下,它与内部和外部参与者进行讨论。

当我进行讨论时,我想立即解析他们对状态不在的参与者的任何引用,将它们分配到填写缺失数据的请求中(这样我就可以显示名称) ,UI上的头像等。如果所有信息都已在本地提供,我不想要求任何信息。

我最初的计划是依靠连接的React组件,这些组件使用数据检查生命周期事件中缺少的引用实体(componentDidMount / componentWillReceiveProps)并调度操作以填充数据,因此史诗可以坚持自己的域而不关心还有什么需要更新。

然而,由于该状态在许多不同的地方被使用,所有这些都需要在必要时进行检查和调度操作,因此这有点失控。尽管我喜欢将状态域保持分离,但我认为使用处理讨论请求的史诗也可以调度更新其他内容的操作将占用更小的空间。原因是,这将释放连接的组件以仅渲染或等待数据,而不是分派更新以填充缺少的引用。但我全力以赴寻求更好的解决方案。

1 个答案:

答案 0 :(得分:1)

empty会返回一个可观察对象,因此根据unknown.length,您的fetchMissingRelations函数将返回(似乎是)一个动作或一个可观察的动作。

你应该改变它,以便它总是返回一个observable:

const fetchMissingRelations = (response: Foo[], state: RootState) => {
  const unknown: BarId[] = foo
    .map(foo => foo.barId)
    .filter(barId => !state.bar.entities[barId])
  return unknown.length
    ? of(actions.bar.fetch([...new Set(unknown)]))
    : empty<never>()
}

您应该更改mergeMap以考虑到这一点:

...
mergeMap(({response}) => concat(
  of(actions.foo.fetchFulfilled(response)),
  fetchMissingRelations(response, store.getState())
)),
相关问题