RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1002003
Accepted
Venta
Venta
Asked:2020-07-12 15:36:46 +0000 UTC2020-07-12 15:36:46 +0000 UTC 2020-07-12 15:36:46 +0000 UTC

NGXS 检索尚未在商店中的元素

  • 772

我研究了 NGXS,发现文档很少,对最佳实践的描述甚至更少。

例如,我有一个客户端数据库,通过一些抽象方法将其信息加载到存储库中。我需要获取有关特定客户的信息。如果它已经在存储中,那么一切都清楚了,我就接受它。但是,如果它还没有被加载到那里,反之亦然。如何让客户正确?

我看到了哪些选项?在解析器中执行此操作,然后保证组件在初始化阶段接收数据。直接在组件中执行此操作,但在我看来,以这种方式加载组件是错误的。通过提供存在性检查的服务来执行此操作,如果它们不存在,则通过订阅将数据传递给组件。最后,在商店本身进行,这对我来说似乎很糟糕,因为那样我还必须在那里进行验证和错误处理,这在我看来违反了一堆正确架构的概念。当然还有其他方法。

但是验证方法本身对我来说也不是很明显。我认为首先您需要拍摄商店的快照,发现其中缺少必要的数据,然后将它们分派。有没有更优雅的选择?

建议如何正确地做这件事,也许有一些东西可以阅读以了解这个主题。

angular
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    overthesanity
    2020-07-12T15:52:51Z2020-07-12T15:52:51Z

    免责声明 - 我是 NGXS 开发人员之一,所以我会尝试给出更详细的答案:)

    例如,我有一个客户端数据库,通过一些抽象方法将其信息加载到存储库中。我需要获取有关特定客户的信息。

    我看到 2 个状态 - clients, client.

    但是,如果它还没有被加载到那里,反之亦然。如何让客户正确?

    有点不清楚,您有一个客户列表,用户可以做什么 - 选择他们并查看信息?您需要在问题中指定,因为例如我不清楚。

    在解析器中执行此操作,然后保证组件在初始化阶段接收数据

    是的,创建一个事件:

    export class GetClients {
      public static readonly type = '[Clients] Get clients';
    }
    

    并将其发送到解析器中:

    export class GetClientsResolver implements Resolve<unknown> {
      constructor(private readonly store: Store) {}
    
      public resolve(): Observable<unknown> {
        return this.store.dispatch(new GetClients());
      }
    }
    

    直接在组件中执行此操作,但在我看来,以这种方式加载组件是错误的。

    不需要,组件最初必须通过选择器接收一个现成的数据块:

    export class ClientsComponent {
      @Select(ClientsState.getClients)
      public clients$: Observable<Client[]>;
    }
    

    最后,在商店本身进行,这对我来说似乎很糟糕,因为那样我还必须在那里进行验证和错误处理,我认为这会违反一系列正确架构的概念。

    这是您的主观意见,但事实并非如此。状态应该隔离某些业务逻辑,以便没有人遍历文件并查找发生了什么、在哪里以及如何发生。

    会打破一堆正确架构的概念

    它会打破什么概念?:)

    我认为首先您需要拍摄商店的快照,发现其中缺少必要的数据,然后分发它们

    为什么每次用户重新加载页面时都要检查一下——他应该看到一个客户列表,对吧?

    PS - 在评论中写更详细的问题,我会更新答案。

    UPD

    如果您在商店中进行检查,则将违反某些 SOLID 原则

    如果您破译 SOLID 首字母缩写词并了解所有原则,则不会违反任何原则 :)

    您无需进行任何验证。看,你有一个根解析器,Angular 将运行 1 次以获取所有客户端:

    const routes: Routes = [
      {
        path: '',
        resolve: [GetClientsResolver],
        children: [
          {
            path: '',
            loadChildren: () => import('path-to-clients-module')
          }
        ]
      }
    ];
    
    export const AppRoutingModule = RouterModule.forRoot(routes);
    

    当你的架构不是“类 Redux”时,错误处理应该在服务中完成。这不适用于组件,因为有时您需要在那里进行一些处理(在需要向用户显示错误的情况下,例如表单验证)。

    当你有状态时,必须在适当的类中进行处理,在 NgRx 中这些是具有效果的类,在 NGXS 中它只是一个具有状态的类。

    否则,存在循环依赖:

    ClientsService -> Actions (GetClientsFailure) -> ClientsState -> ClientsService
    

    原则上,我认为错误处理没有问题,例如,我们想加载一个客户端列表,但我们的容器已经下降(假设)并且 Nginx 返回 504:

    @State<Client[]>({
      name: 'clients',
      defaults: []
    })
    export class ClientsState {
      constructor(private readonly clientsService: ClientsService) {}
    
      @Action(GetClients)
      public getClients({ setState }: StateContext<Client[]>) {
        return this.clientsService.getClients().pipe(
          tap(clients => setState(clients)),
          catchError(() => {
            setState([]);
            return of(null);
          })
        );
      }
    }
    

    它在哪里clientsService.getClients:

    return this.http.get('/api/clients');
    

    也许我误解了您的问题-如何加载具有验证功能的客户端等,如果您已经有了它们的列表-那么您是否需要按ID加载客户端,从数组中获取它不是更容易吗?

    也许如果客户端列表包含有关它们的不完整信息,但只有一些最小的信息,例如id, name,那么您可以创建一个附加状态,例如clientsInfo,它将获取所需的客户端id或下载它:

    type ClientsInfoStateModel = { [key: string]: Client };
    
    export class GetClientById {
      public static readonly type = '[Clients info] Get client by ID';
      constructor(public id: string) {}
    }
    
    @State<ClientsInfoStateModel>({
      name: 'clientsInfo',
      defaults: {}
    })
    export class ClientsInfoState {
      public static getClientById(id: string) {
        return createSelector(
          [ClientsInfoState],
          (state: ClientsInfoStateModel) => state[id]
        );
      }
    
      constructor(private readonly clientsService: ClientsService) {}
    
      @Action(GetClientById)
      public getClientById(
        { getState, patchState }: StateContext<ClientsInfoStateModel>,
        { id }: GetClientById
      ) {
        return this.clientsService.getClientById(id).pipe(
          tap(client => {
            patchState({
              [id]: client
            });
          })
        );
      }
    }
    

    public static getClientByIdid是一个选择器,它将通过它的, 或undefined(如果它不存在)从缓存中返回有关客户端的完整信息。

    然后在解析器中,您需要检查:

    export class GetClientByIdResolver implements Resolve<Client> {
      constructor(private readonly store: Store) {}
    
      public resolve(route: ActivatedRouteSnapshot): Client | Observable<Client> {
        const id = route.paramMap.get('id');
        const client = this.store.selectSnapshot(ClientsInfoState.getClientById(id));
    
        if (client) {
          return client;
        }
    
        return this.store.dispatch(new GetClientById(id)).pipe(
          map(() => this.store.selectSnapshot(ClientsInfoState.getClientById(id)))
        );
      }
    }
    

    在组件本身中,我们已经获得了有关客户端的所有信息:

    export class ClientInfoComponent {
      public client = this.route.data.snapshot.client;
    
      constructor(private readonly route: ActivatedRoute) {}
    }
    
    • 2

相关问题

  • 为什么排序在 mat-table 中不起作用?

  • 角度材料在角度 7 中不起作用

  • 以角度循环显示图像

  • Angular 密码比较验证器

  • 如何在 Angular 6 上向 sidenav 添加下拉元素?[关闭]

  • 一个组件中有两个指令。冲突

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5