有没有什么办法可以简化 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/