Is there any way to simplify the definition of actions so that we don't need to repeat code over and over again?
Problem
Working with Ngrx we have to work with actions all the time. In my situation, the most time each action does have a "Do"-Action, a "Success"-Action and a "Failure"-Action. In my situation each of these actions does have the same scope (e.g. "[Authentication]") and the same label (e.g. "Login user").
When I want to create actions for user authentication I would create these as follows:
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;
}
);
As you can see there is a lot of repetition:
- three "[Authentication]" for the same scope
- three "Login user" for the same kind of action
- the "DO", "SUCCESS", "FAILURE" parts are the same in all actions
Is there any way to create a factory that simplifies the action creation with less redundant code?
My current solution
See my answer to this post.
I created a package ngrx-simple with the goal of simplifying ngrx development. It implements a class SimpleActions that helps to group actions and reduce code repetition:
https://github.com/julianpoemp/ngrx-simple
My old solution
(the code in the new package is better)
The only simplification I found so far is creating a class of actions of the same scope and wrap all actions for the same kind of action in an object:
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');
}
I see my solution as workaround only. Although it saves me 10 lines of code, it isn't optimal...