1

我是 redux 可观察对象的新手:https ://github.com/redux-observable/redux-observable

我有一个简单的用例,我想根据用户的signedIn状态做两件不同的事情。

  1. 如果已登录,请添加 rsvp
  2. 如果未登录,则显示登录模式

我的app/redux/epics/addRSVP.js文件中有这个:

import 'rxjs';
import * as scheduleActions from '../ducks/schedule';

export default function searchUsers(action$, store) {
  return action$.ofType(scheduleActions.ADD_RSVP)
    .filter(() => store.getState().user.signedIn)
    .map(action => scheduleActions.rsvpAdded(action.payload));
};

我的问题是,我应该app/redux/epics/preventRSVPIfNotSignedIn.js为已注销的用例创建另一个史诗吗?就像是:

import 'rxjs';
import * as authenticationActions from '../ducks/authentication';

export default function searchUsers(action$, store) {
  return action$.ofType(scheduleActions.ADD_RSVP)
    .filter(() => !store.getState().user.signedIn)
    .map(action => authenticationActions.show());
};

或者有没有办法可以将两者放在同一个文件中?如果是前者,我觉得它最终会成为很多史诗。很高兴知道一般约定是什么。

4

2 回答 2

4

Sebastian 给出了很好的建议,通常我会将它们分开并复制逻辑。但是,如果你真的经常这样做,你可以创建自己的抽象,这样你就不需要重复自己了。

您可以创建一个像requireAuth这样的助手来执行您预期的操作,也可以创建一个仅在具有有效身份验证时才应该接收这些操作的史诗。然后它将返回一个包装它的新史诗。

// Helper to abstract the common auth requirement checks
// which will also dispatch authenticationActions.show()
// when they attempt to do something they can't
const requireAuth = (type, epic) => (action$, store) => {
  // matching actions which they have permission for
  const valid$ = action$
    .ofType(type)
    .filter(() => store.getState().user.signedIn);

  // matching actions they do NOT have permission for
  const invalid$ = action$
    .ofType(type)
    .filter(() => !store.getState().user.signedIn);

  return Observable.merge(
    epic(valid$, store),
    invalid$.map(action => authenticationActions.show())
  );
};

const searchUsersEpic = requireAuth(scheduleActions.ADD_RSVP, (action$, store) =>
  action$.map(action => scheduleActions.rsvpAdded(action.payload))
);

// You can then use requireAuth for any epics that require it
// as an example:
const searchMoviesEpic = requireAuth(scheduleActions.SEARCH_MOVIE, (action$, store) =>
  action$.mergeMap(action =>
    ajax(`/search/for/the/movie/${action.id}`)
      .map(resp => scheduleActions.searchMoviesFulfilled(resp))
  )
);

根据需要进行调整——但要小心,添加抽象可能会使您的代码库以后难以推理,或者当有人稍后调整抽象而没有意识到它如何影响其他代码路径时引入错误。测试变得更重要!

于 2017-03-20T22:48:06.937 回答
3

如果您不确定,请始终创建单独的史诗。以后更容易测试和更改。另外,这种方法几乎没有缺点(性能方面)。结合两个史诗是一种在不知道是否真的有必要的情况下添加抽象。

此外,从外观上看,这两种(副作用)效果的范围是不同的。我会说这是一个强有力的指标,表明在这里使用单独的史诗是一个好主意,并且将在未来得到更多的证明。

也就是说,如果你确定你的史诗不会改变或变得更复杂(目前是 if/else),我想这也很好。


再看一遍后,我想您想要做的是“如果用户未登录,请向我显示登录页面并等到(她)他登录并在成功登录后触发 RSVP 操作”。如果这是您的用例,您可能需要查看delayWhen. 这可能是一个更好的解决方案,但它更像是 RxJS 的一个高级特性。当您更习惯时,也许这是重构的一项好任务redux-observables:)

于 2017-03-20T13:06:07.227 回答