使用带有 typesafe-actions 和 Connected React Router 的史诗

Posted

技术标签:

【中文标题】使用带有 typesafe-actions 和 Connected React Router 的史诗【英文标题】:Usage of epics with typesafe-actions and Connected React Router 【发布时间】:2020-04-12 22:10:50 【问题描述】:

我目前正在设置一个侦听LOCATION_CHANGELocationChangeAction 类型的动作的史诗,这是每当路由器历史记录由于pushreplace 等路由器动作而发生变化时触发的动作.

import  LOCATION_CHANGE, LocationChangeAction  from 'connected-react-router';
import  isActionOf  from 'typesafe-actions';

const locationEpic: Epic = (action$) => action$.pipe(
  filter(isActionOf(LocationChangeAction)),
  tap((action) => 
    // do the rest here

  )
);

但是,执行上述操作会引发错误,并且添加 typeof 似乎也无济于事。

'LocationChangeAction' only refers to a type, but is being used as a value here.

我可以知道使用typesafe-actions的正确方法是什么吗? 的isActionOf() 运算符?

【问题讨论】:

您能否在问题中添加您的操作定义? 我认为你必须使用onLocationChanged 而不是LocationChangeAction。 Source @AndreiGătej 错误不再显示,但现在控制台返回以下错误Argument contains array with invalid element at index 0, it should be an action-creator instance from "typesafe-actions"。知道如何解决这个问题吗? 【参考方案1】:

除了 Andrei 的出色回答之外,我想提出一个替代解决方案来解决我的问题。

显式定义“假”操作以反映来自connected-react-router(例如pushreplaceonLocationChanged)的历史操作方法的问题在于,它会在您需要时解决进一步的下游问题呼叫/聆听您史诗的动作(例如redux-observables)。

因此,处理此问题的更好方法是在主 RootAction 上添加 History 操作方法的类型。例如,如果您希望将 replace 操作添加为 Redux RootAction 的一部分,

import  CallHistoryMethodAction, connectRouter, RouterState  from 'connected-react-router';
import  LocationState, Path  from 'history';

const actions = 
  userActions,
  settingsActions
;

type Replace = (path: Path, state?: LocationState) => CallHistoryMethodAction<[Path, LocationState?]>;

interface RouteActions 
  replace: Replace;


export type RootAction = ActionType<typeof actions> | ActionType<RouteActions>;

export interface RootState 
  router: RouterState;
  user: UserState;
  settings: SettingsState;

这将防止TypeScript/typesafe-actions 标记您的历史操作未定义的错误。

【讨论】:

【参考方案2】:

参考

参数包含索引为 0 的无效元素的数组,它应该是来自“typesafe-actions”的动作创建器实例

它可能会抛出该错误,因为ActionCreator 包含需要getType?: () =&gt; TType 的ActionCreatorTypeMetadata:

type TypeConstant = string;

export interface ActionCreatorTypeMetadata<TType extends TypeConstant> 
  getType?: () => TType;

ActionCreator
export type ActionCreator<T extends  type: string > = ((
  ...args: any[]
) => T) &
  ActionCreatorTypeMetadata<T['type']>;

但是,onLocationChanged 函数只实现了交集的第一部分(一个返回具有属性type 的对象的函数)。

export const LOCATION_CHANGE = '@@router/LOCATION_CHANGE'

export const onLocationChanged = (location, action, isFirstRendering = false) => (
  type: LOCATION_CHANGE,
  payload: 
    location,
    action,
    isFirstRendering,
  
)

该函数还必须包含一个属性getType

onLocationChanged.getType = () => `YOUR_TYPE`.

TypeScript Playground


对于使用typesafe-actions的用户,您需要注册LOCATION_CHANGE操作,

import  LOCATION_CHANGE, RouterActionType  from 'connected-react-router';
import  Location  from 'history';
import  createAction  from 'typesafe-actions';

namespace RouterActions 

  export const onLocationChanged = createAction(
    LOCATION_CHANGE,
    (action) => (location: Location, routerAction: RouterActionType, isFirstRendering?: boolean) => action(
      location,
      action: routerAction,
      isFirstRendering,
    ),
  );


export default RouterActions;

在您的史诗中,您可以简单地收听LOCATION_CHANGE 操作,

const locationEpic: Epic = (action$) => action$.pipe(
  filter(isActionOf(RouterActions.onLocationChanged)),
  switchMap((epic) => 
    // do the rest
  ),

);

【讨论】:

知道了!谢谢您的帮助!解决方法是创建一个镜像 LOCATION_CHANGE 的类型安全操作,以便将其识别为有效操作。 很高兴它有帮助!这是一个有趣的问题!:) 你好!感谢您几个月前帮助我!我想我找到了替代解决方案。如果您遇到此问题,您可能需要参考它:) 感谢您告诉我!

以上是关于使用带有 typesafe-actions 和 Connected React Router 的史诗的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自动工具编译带有 clang 和选项 -std=c++11 的项目

无法在带有 VS2017 的 Windows 10 上安装和使用 gRPC C/C++

使用带有扩展和自定义功能的 groupby

带有 Qt/c++ 和 openseemap 的桌面地图应用程序

带有可变参数的 Swift 和 C 回调

如何使用 PyOpenCL 将带有数组和变量的 C 结构传递给 OpenCL 内核