reactjs - typescript redux 操作:组合与继承
问题描述
在与typescript 一起使用的 redux 手册中,他们将操作类型定义为:
// src/store/chat/types.ts
export const SEND_MESSAGE = 'SEND_MESSAGE'
export const DELETE_MESSAGE = 'DELETE_MESSAGE'
interface SendMessageAction {
type: typeof SEND_MESSAGE
payload: Message
}
interface DeleteMessageAction {
type: typeof DELETE_MESSAGE
meta: {
timestamp: number
}
}
export type ChatActionTypes = SendMessageAction | DeleteMessageAction
这很是一种类型的组合。
相反,您可以这样定义它们:
BaseAction.ts:
export interface BaseAction {
type: any;
payload: any;
}
具体操作.ts:
export enum SpecificActionType {
SPECIFIC_ACTION_1 = "action1",
SPECIFIC_ACTION_2 = "action2",
}
export interface SpecifcAction extends BaseAction {
type: SpecificActionType;
}
export const SpecificAction1 = (param: SomeType): SpecifcAction => ({
type: SpecificActionType.SPECIFIC_ACTION_1,
payload: {
stream
},
});
export const SpecificAction2 = (param: SomeType): SpecifcAction => ({
type: SpecificActionType.SPECIFIC_ACTION_2,
payload: {
uid
}
});
这第二个基于继承的选项对我来说似乎更直观,因为它允许我为我的应用程序的不同方面创建不同的操作文件 - 无需修改原始 BaseAction.ts 文件。
作为旁注,看看创建一个SpecificAction1
有点像 scala 案例类的感觉 - 如果只有 typescript 有这个范式,那么payload
对于 redux 对动作类型的模式匹配的智能感知和语法糖会很好。
不过,你可以在减速器上做这样的事情:
具体Reducer.ts:
export const mySpecificReducer = (
state: MyState = initialState,
action: SpecifcAction
): MyState => {
switch (action.type) {
case SpecificActionType.SPECIFIC_ACTION_1:
console.log("add stream action");
return {<change state accordingly>};
case SpecificActionType.SPECIFIC_ACTION_2:
return {<change state accordingly>};
default:
return state;
}
};
我的问题:这里有什么缺点?
- 看起来这更好地遵循了打开/关闭原则,尽管我们可以这样说。
- 它可能会增加一些复杂性,但我假设您的应用程序中有多个方面具有固有的不同操作,因此这可能有助于更好地管理所述复杂性。
- 最后,您可以将 ActionTypes 作为 Enums 更好地管理,如果您使用带有智能感知的 IDE,它将帮助您管理选项。
我是否在不知不觉中射中自己的脚?
解决方案
从概念上讲,我只想定义从每个动作类型到有效负载形状的映射。所以我决定使用可区分联合并尽可能多地删除类型系统语法。
使用这种方法可以让 Typescript 保护我们免于使用错误的有效负载编写动作创建者,或制作拼写错误。
老实说,在大型项目中使用 Redux 最困难的部分是编写所有样板文件,因此我尽量将其保持在最低限度。
export type IceCreamActionShapes = {
type: IceCreamActionTypeKeys.SET_FLAVOR;
payload: string;
} | {
type: IceCreamActionTypeKeys.CREATE_FLAVOR;
payload: IFlavor;
} | {
type: IceCreamActionTypeKeys.MELT;
}
我不认为应用程序的任何复杂性都应该由 redux 操作调度层管理。但是,您的示例BaseAction
仍然非常简单。即使您IceCreamBaseAction
为每只鸭子添加了特定于域的 BaseAction,它仍然很容易维护,因为它是打开/关闭的。
我总是使用字符串枚举作为操作键。键是可重构和可搜索的,您可以向字符串值添加额外的上下文信息。
推荐阅读
- druid - 从逗号 sep 字符串中提取多值维度
- c# - 什么是 FixedUpdate 以及它如何在 unity3d 中运行
- javascript - 使用 appname 和命名空间在 django 模板 url 中动态添加 js 变量值
- json - 转换 json 以添加数组对象
- flutter - 有没有办法为传入的嵌套响应生成具有通用结果属性的响应模型?
- php - 错误 404 - 未找到您要查找的文档已删除/重命名
- wordpress - 我想将提交的重力表单条目获取到另一个重力表单(wordpress)
- wordpress - 无效的分类 Wordpress
- android - 如何修复“[Dagger/MissingBinding]:没有@Provides-annotated 方法就无法提供”
- angular - 使用 observable 触发多个 API 调用