如何在Action构造时添加默认属性,统一处理成功事件提示?
方案可行性分析与替代方案
原方案可行性
你的方案完全可行,能实现预期需求:在Action中一次性定义翻译键,通过统一Effect触发对应成功提示。但它存在明显的维护痛点:每次新增成功Action时,必须手动把Action添加到ofType的参数列表中,长期迭代容易遗漏,扩展性较差。
更优替代方案
以下是几种更通用的实现方式,避免逐个维护Action列表:
1. 利用Action元数据(Meta)标记翻译键
将翻译键放在Action的meta字段中(而非业务props),既不污染业务数据,又能让Effect批量过滤处理符合条件的Action:
修改Action定义
// list.action.ts export const listActions = createActionGroup({ source: 'List', events: { 'Delete Success': { props: () => ({ id: number }), meta: { translationKey: 'list.delete.success' } }, } }); // detail.action.ts export const detailActions = createActionGroup({ source: 'Detail', events: { 'Add Success': { props: () => ({ data: DetailItem }), meta: { translationKey: 'detail.add.success' } }, 'Update Success': { props: () => ({ data: DetailItem }), meta: { translationKey: 'detail.update.success' } } } });
通用Effect实现
// 建议放在全局Effect文件(如app.effects.ts),而非模块内 actionSuccessful$ = createEffect( () => { return this.actions$.pipe( // 过滤所有含Success标识且带有translationKey元数据的Action filter(action => action.type.includes('Success') && action.meta?.translationKey), map(action => this.snackbarService.success({ translationKey: action.meta.translationKey })) ); }, { dispatch: false } );
优势:新增成功Action时,只需在meta中配置翻译键,无需修改Effect,完全解耦模块与全局提示逻辑。
2. 基于命名约定自动生成翻译键
如果你的Action命名和翻译键有严格对应关系(比如[List] Delete Success对应list.delete.success),可以通过解析Action的type字段自动生成翻译键,无需手动配置:
翻译键生成函数
const getTranslationKeyFromAction = (actionType: string): string => { // 解析格式:"[Source] Event Name Success" const [sourcePart, eventPart] = actionType.split('] '); const source = sourcePart.slice(1).toLowerCase(); // 提取[List]中的List并转小写 const event = eventPart.replace(/\s+/g, '.').toLowerCase(); // 把"Delete Success"转为delete.success return `${source}.${event}`; };
通用Effect实现
actionSuccessful$ = createEffect( () => { return this.actions$.pipe( filter(action => action.type.includes('Success')), map(action => { const translationKey = getTranslationKeyFromAction(action.type); return this.snackbarService.success({ translationKey }); }) ); }, { dispatch: false } );
优势:完全无需在Action中配置额外字段,靠命名约定自动适配翻译文件,零重复代码。如果有特殊翻译键需要自定义,可以结合方案1的meta字段做覆盖。
3. 类型守卫过滤成功Action
定义通用的成功Action类型,通过类型守卫过滤所有符合该类型的Action:
定义成功Action接口
interface SuccessAction { translationKey: string; // 可选:添加其他公共属性 }
修改Action定义
export const listActions = createActionGroup({ source: 'List', events: { 'Delete Success': props<{ id: number; translationKey: 'list.delete.success' }>(), } });
通用Effect实现
actionSuccessful$ = createEffect( () => { return this.actions$.pipe( // 类型守卫:判断Action是否包含translationKey字段 filter((action): action is SuccessAction => 'translationKey' in action), map(({ translationKey }) => this.snackbarService.success({ translationKey })) ); }, { dispatch: false } );
优势:无需手动列举Action,只要Action包含translationKey就会被处理,适合不想用meta的场景。
总结
原方案能满足需求,但扩展性不足。推荐优先使用方案1(Meta元数据),它兼顾灵活性和可维护性;如果翻译键和Action命名完全匹配,**方案2(自动生成)**是最简洁的选择。
内容的提问来源于stack exchange,提问作者Vevl
相关产品推荐
相关产品推荐

