angular - Ngrx:如何简化 Action 的定义?

标签 angular typescript ngrx ngrx-store

有没有什么办法可以简化 Action 的定义,让我们不需要一遍又一遍地重复代码?

问题

在使用 Ngrx 时,我们必须始终处理操作。在我的情况下,大多数时候每个 Action 确实有一个“执行”- Action 、一个“成功”- Action 和一个“失败”- Action 。在我的情况下,这些操作中的每一个都具有相同的范围(例如“[Authentication]”)和相同的标签(例如“登录用户”)。

当我想为用户身份验证创建操作时,我会按如下方式创建这些操作:

export const loginUser = createAction(
    '[Authentication] DO: Login user',
    props<{
      username: string;
      password: string;
    }
);

export const loginUserSuccess = createAction(
    '[Authentication] SUCCESS: Login user',
    props<{
      token: string;
    }
);

export const loginUserFailure = createAction(
    '[Authentication] FAILURE: Login user',
    props<{
      error: string;
    }
);

如您所见,有很多重复:

  • 相同范围的三个“[身份验证]”
  • 同一类操作的三个“登录用户”
  • “DO”、“SUCCESS”、“FAILURE”部分在所有操作中都是相同的

有没有什么方法可以创建一个工厂,用更少的冗余代码来简化 Action 的创建?

我目前的解决方案

查看我对这篇文章的回答。

我创建了一个包 ngrx-simple,目的是简化 ngrx 开发。它实现了一个 SimpleActions 类,有助于对操作进行分组并减少代码重复:

https://github.com/julianpoemp/ngrx-simple


我的旧解决方案

(新包里的代码更好)

到目前为止,我发现的唯一简化是创建一个具有相同作用域的 Action 类,并将同类 Action 的所有 Action 包装在一个对象中:

store.functions.ts

import {createAction, props} from '@ngrx/store';

export function createDoActionType(scope: string, label: string) {
  return `[${scope}] DO: ${label}`;
}

export function createSuccessActionType(scope: string, label: string) {
  return `[${scope}] SUCCESS: ${label}`;
}

export function createErrorAction(scope: string, label: string) {
  return createAction(
    `[${scope}] FAILURE: ${label}`,
    props<ErrorProps>()
  );
}

export interface ErrorProps {
  error: string;
}

authentication.actions.ts

export class AuthenticationActions {
  private static scope = 'Authentication';

    static loginUser = ((scope: string, label: string) => ({
    do: createAction(
      createDoActionType(scope, label),
      props<{
        userEmail: string;
        password: string;
      }>()
    ),
    success: createAction(
      createSuccessActionType(scope, label),
      props<{
        userID: number;
        token: string;
      }>()
    ),
    failure: createErrorAction(scope, label)
  }))(AuthenticationActions.scope, 'Login user');
}

我认为我的解决方案只是解决方法。虽然它为我节省了 10 行代码,但它并不是最佳的...

最佳答案

我的公司已经开源了一个库来处理这个作为 ngrx 的扩展。

https://github.com/acandylevey/ngrx-http-tracking

使用 createTrackingActions,创建了 3 个 Action :

  • 加载 -> 请求
  • 加载
  • 失败
const actionNameSpace = 'Users';

(...)

//                                         Request type     Response Type
//                                                \/          \/   
export const fetchUsers = createTrackingActions<UserRequest, User[]>(
  actionNameSpace,
  'fetchUsers'
);

与之相结合的是 createTrackingEffect 函数,该函数接受由 createTrackingActions 创建的 Action 并连接 3 个带下划线的 Action

import { UserApiService } from './user-api.service';
import * as UserActions from './user.actions';

(...)

fetchUsers$ = createTrackingEffect(
    this.actions$,
    UserActions.fetchUsers,
    this.userApi.fetchUsers,
    'Could not load users' // there is a final optional function argument here to allow further function calls after the action is processed.
  );

而且 reducer 也被简化了,因为通常只需要处理 loaded Action :

const usersReducer = createReducer(
  initialState,
  on(UserActions.fetchUsers.loaded, (state, { payload }) =>
    userssAdapter.setAll(payload, { ...state })
  )
);

跟踪结果

默认情况下,所有操作都标记有全局标记,然后可以在全局级别轻松拦截该标记,以提供全局错误处理或全局加载微调器(如果有任何操作正在等待 http 请求)。

httpTrackingFacade 也是lib提供的

isLoaded$ = this.httpTracker.isLoaded(UserActions.fetchUsers);
 isLoading$ = this.httpTracker.isLoading(UserActions.fetchUsers);

 isGloballyLoading$ = this.httpTrackingFacade.getGlobalLoading();
 globalErrors$ = this.httpTrackingFacade.getGlobalErrors();

并跟踪个人行为有

从门面触发请求

 fetchUsers() {
    this.store.dispatch(UserActions.fetchUsers.loading());
    return UserActions.fetchUsers;
  }

追踪它

  this.httpTrackingFacade
      .getResolved(this.userFacade.fetchUsers())
      .subscribe((result) => {
        console.log(`The result from the fetch users call was: {result}`);
      });

关于angular - Ngrx:如何简化 Action 的定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70621518/

相关文章:

javascript - 通过键查找 json 对象并将其替换为复杂/嵌套 json 数组中的其他对象

jquery - 为什么我的 bootstrap 轮播不能正常工作?

angular - Angular 10 中有任何 json 编辑器吗?

html - Angular 2上传多个文件

typescript - 如何获取和设置 div.class 高度

angular - NGRX 选择器在商店可用之前请求数据

typescript - 有没有办法部分匹配 Typescript 字符串类型?

typescript - 为什么 http.post 没有在 Angular 2 中调用我的 Controller

javascript - 在 Angular 5 中,如何对点击事件进行分组并仅在用户停止点击时发出一次

angular - 发送 :false 时测试@Effect