You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将通用NGRX Action作为参数传入抽象CRUD服务?

实现基于NgRx Action的通用CRUD抽象服务

核心思路

通过TypeScript泛型+类型别名统一Action调用方式,将CRUD的通用逻辑封装在抽象类中,让具体实体组件仅需传入对应Action的包装函数即可复用逻辑。

步骤1:定义通用Action类型别名

先统一Add/Update/Delete Action的类型,适配不同实体Action的参数结构差异:

import { Action } from '@ngrx/store';

// 统一Add/Update Action的调用签名:接收实体T,返回NgRx Action
type CRUDAction<T> = (entity: T) => Action;
// Delete Action的调用签名:接收id,返回NgRx Action
type DeleteAction = (id: number) => Action;

步骤2:完善抽象CRUD服务类

抽象类注入Store,通过构造函数接收Action包装函数,实现通用的save和delete逻辑:

import { Component, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { Action } from '@ngrx/store';

type CRUDAction<T> = (entity: T) => Action;
type DeleteAction = (id: number) => Action;

// 泛型约束确保实体必须包含id字段
@Component({ template: '' })
export abstract class CRUDService<T extends { id: number }> {
  // 抽象类直接注入Store,子类无需重复注入
  protected readonly store = inject(Store);

  constructor(
    private addAction: CRUDAction<T>,
    private updateAction: CRUDAction<T>,
    private deleteAction: DeleteAction
  ) {}

  saveEntry = (entity: T) => {
    // 可在此添加通用验证、添加通用字段(如更新时间)等逻辑
    const updatedEntity = { ...entity /* , updatedAt: new Date() */ };
    
    // 根据id判断是新增还是更新
    entity.id === 0
      ? this.store.dispatch(this.addAction(updatedEntity))
      : this.store.dispatch(this.updateAction(updatedEntity));
  };

  deleteEntry = (entity: T) => {
    this.store.dispatch(this.deleteAction(entity.id));
  };
}

步骤3:具体实体组件继承抽象类

以Groups组件为例,传入对应Action的包装函数即可复用CRUD逻辑:

import { Component, inject } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { CRUDService } from './crud.service';
import { GroupModel } from './group.model';
import { GroupsActions } from './groups.actions';

@Component({
  selector: 'app-crud-groups',
  template: `<!-- 具体组件模板 -->`
})
export class CRUDGroupsComponent extends CRUDService<GroupModel> {
  // 子类注入自身需要的服务(如FormBuilder)
  private readonly fb = inject(FormBuilder);

  constructor() {
    // 传入适配后的Action包装函数,统一成抽象类需要的调用签名
    super(
      (group) => GroupsActions.addGroup({ group }),
      (group) => GroupsActions.updateGroup({ group }),
      (id) => GroupsActions.removeGroup({ id })
    );
  }
}

Shapes和Colors组件的实现逻辑完全一致,只需替换对应的Action和实体类型即可。

内容的提问来源于stack exchange,提问作者Starfish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:54:59