Skip to content

Commit 0991032

Browse files
authored
Debt: Simplifies actionCreatorFactory (grafana#19433)
- Use sets to keep track of previously defined actionCreators - Remove noPayloadActionCreatorFactory
1 parent 651b59b commit 0991032

File tree

8 files changed

+32
-73
lines changed

8 files changed

+32
-73
lines changed
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { noPayloadActionCreatorFactory } from 'app/core/redux';
1+
import { actionCreatorFactory } from 'app/core/redux';
22

3-
export const toggleLogActions = noPayloadActionCreatorFactory('TOGGLE_LOG_ACTIONS').create();
3+
export const toggleLogActions = actionCreatorFactory('TOGGLE_LOG_ACTIONS').create();

public/app/core/redux/actionCreatorFactory.test.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
actionCreatorFactory,
3-
resetAllActionCreatorTypes,
4-
noPayloadActionCreatorFactory,
5-
} from './actionCreatorFactory';
1+
import { actionCreatorFactory, resetAllActionCreatorTypes } from './actionCreatorFactory';
62

73
interface Dummy {
84
n: number;
@@ -18,7 +14,7 @@ interface Dummy {
1814
const setup = (payload?: Dummy) => {
1915
resetAllActionCreatorTypes();
2016
const actionCreator = actionCreatorFactory<Dummy>('dummy').create();
21-
const noPayloadactionCreator = noPayloadActionCreatorFactory('NoPayload').create();
17+
const noPayloadactionCreator = actionCreatorFactory('NoPayload').create();
2218
const result = actionCreator(payload);
2319
const noPayloadResult = noPayloadactionCreator();
2420

@@ -49,7 +45,7 @@ describe('actionCreatorFactory', () => {
4945
setup(payload);
5046

5147
expect(() => {
52-
noPayloadActionCreatorFactory('DuMmY').create();
48+
actionCreatorFactory('DuMmY').create();
5349
}).toThrow();
5450
});
5551
});

public/app/core/redux/actionCreatorFactory.ts

+12-24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Action } from 'redux';
22

3-
const allActionCreators: string[] = [];
3+
const allActionCreators = new Set<string>();
44

55
export interface ActionOf<Payload> extends Action {
66
readonly type: string;
@@ -25,33 +25,21 @@ export interface NoPayloadActionCreatorFactory {
2525
create: () => NoPayloadActionCreator;
2626
}
2727

28-
export const actionCreatorFactory = <Payload>(type: string): ActionCreatorFactory<Payload> => {
29-
const create = (): ActionCreator<Payload> => {
30-
return Object.assign((payload: Payload): ActionOf<Payload> => ({ type, payload }), { type });
31-
};
32-
33-
if (allActionCreators.some(t => (t && type ? t.toLocaleUpperCase() === type.toLocaleUpperCase() : false))) {
34-
throw new Error(`There is already an actionCreator defined with the type ${type}`);
28+
export function actionCreatorFactory<Payload extends undefined>(type: string): NoPayloadActionCreatorFactory;
29+
export function actionCreatorFactory<Payload>(type: string): ActionCreatorFactory<Payload>;
30+
export function actionCreatorFactory<Payload>(type: string): ActionCreatorFactory<Payload> {
31+
const upperCaseType = type.toLocaleUpperCase();
32+
if (allActionCreators.has(upperCaseType)) {
33+
throw new Error(`An actionCreator with type '${type}' has already been defined.`);
3534
}
3635

37-
allActionCreators.push(type);
36+
allActionCreators.add(upperCaseType);
3837

39-
return { create };
40-
};
41-
42-
export const noPayloadActionCreatorFactory = (type: string): NoPayloadActionCreatorFactory => {
43-
const create = (): NoPayloadActionCreator => {
44-
return Object.assign((): ActionOf<undefined> => ({ type, payload: undefined }), { type });
38+
const create = (): ActionCreator<Payload> => {
39+
return Object.assign((payload: Payload): ActionOf<Payload> => ({ type, payload }), { type });
4540
};
46-
47-
if (allActionCreators.some(t => (t && type ? t.toLocaleUpperCase() === type.toLocaleUpperCase() : false))) {
48-
throw new Error(`There is already an actionCreator defined with the type ${type}`);
49-
}
50-
51-
allActionCreators.push(type);
52-
5341
return { create };
54-
};
42+
}
5543

5644
export interface NoPayloadActionCreatorMock extends NoPayloadActionCreator {
5745
calls: number;
@@ -73,4 +61,4 @@ export const mockActionCreator = (creator: ActionCreator<any>) => {
7361
};
7462

7563
// Should only be used by tests
76-
export const resetAllActionCreatorTypes = () => (allActionCreators.length = 0);
64+
export const resetAllActionCreatorTypes = () => allActionCreators.clear();

public/app/features/admin/state/actions.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { actionCreatorFactory, noPayloadActionCreatorFactory } from 'app/core/redux';
1+
import { actionCreatorFactory } from 'app/core/redux';
22
import config from 'app/core/config';
33
import { ThunkResult, SyncInfo, LdapUser, LdapConnectionInfo, LdapError, UserSession, User } from 'app/types';
44
import {
@@ -20,15 +20,15 @@ export const ldapConnectionInfoLoadedAction = actionCreatorFactory<LdapConnectio
2020
export const ldapSyncStatusLoadedAction = actionCreatorFactory<SyncInfo>('ldap/SYNC_STATUS_LOADED').create();
2121
export const userMappingInfoLoadedAction = actionCreatorFactory<LdapUser>('ldap/USER_INFO_LOADED').create();
2222
export const userMappingInfoFailedAction = actionCreatorFactory<LdapError>('ldap/USER_INFO_FAILED').create();
23-
export const clearUserMappingInfoAction = noPayloadActionCreatorFactory('ldap/CLEAR_USER_MAPPING_INFO').create();
24-
export const clearUserErrorAction = noPayloadActionCreatorFactory('ldap/CLEAR_USER_ERROR').create();
23+
export const clearUserMappingInfoAction = actionCreatorFactory('ldap/CLEAR_USER_MAPPING_INFO').create();
24+
export const clearUserErrorAction = actionCreatorFactory('ldap/CLEAR_USER_ERROR').create();
2525
export const ldapFailedAction = actionCreatorFactory<LdapError>('ldap/LDAP_FAILED').create();
2626

2727
export const userLoadedAction = actionCreatorFactory<User>('USER_LOADED').create();
2828
export const userSessionsLoadedAction = actionCreatorFactory<UserSession[]>('USER_SESSIONS_LOADED').create();
29-
export const userSyncFailedAction = noPayloadActionCreatorFactory('USER_SYNC_FAILED').create();
30-
export const revokeUserSessionAction = noPayloadActionCreatorFactory('REVOKE_USER_SESSION').create();
31-
export const revokeAllUserSessionsAction = noPayloadActionCreatorFactory('REVOKE_ALL_USER_SESSIONS').create();
29+
export const userSyncFailedAction = actionCreatorFactory('USER_SYNC_FAILED').create();
30+
export const revokeUserSessionAction = actionCreatorFactory('REVOKE_USER_SESSION').create();
31+
export const revokeAllUserSessionsAction = actionCreatorFactory('REVOKE_ALL_USER_SESSIONS').create();
3232

3333
// Actions
3434

public/app/features/dashboard/panel_editor/state/actions.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { actionCreatorFactory, noPayloadActionCreatorFactory } from '../../../../core/redux';
1+
import { actionCreatorFactory } from '../../../../core/redux';
22
import { PanelEditorTabIds, PanelEditorTab, getPanelEditorTab } from './reducers';
33
import { ThunkResult } from '../../../../types';
44
import { updateLocation } from '../../../../core/actions';
@@ -12,7 +12,7 @@ export const panelEditorInitCompleted = actionCreatorFactory<PanelEditorInitComp
1212
'PANEL_EDITOR_INIT_COMPLETED'
1313
).create();
1414

15-
export const panelEditorCleanUp = noPayloadActionCreatorFactory('PANEL_EDITOR_CLEAN_UP').create();
15+
export const panelEditorCleanUp = actionCreatorFactory('PANEL_EDITOR_CLEAN_UP').create();
1616

1717
export const refreshPanelEditor = (props: {
1818
hasQueriesTab?: boolean;

public/app/features/dashboard/state/actions.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Services & Utils
22
import { getBackendSrv } from '@grafana/runtime';
3-
import { actionCreatorFactory, noPayloadActionCreatorFactory } from 'app/core/redux';
3+
import { actionCreatorFactory } from 'app/core/redux';
44
import { createSuccessNotification } from 'app/core/copy/appNotification';
55
// Actions
66
import { loadPluginDashboards } from '../../plugins/state/actions';
@@ -19,11 +19,11 @@ import {
1919

2020
export const loadDashboardPermissions = actionCreatorFactory<DashboardAclDTO[]>('LOAD_DASHBOARD_PERMISSIONS').create();
2121

22-
export const dashboardInitFetching = noPayloadActionCreatorFactory('DASHBOARD_INIT_FETCHING').create();
22+
export const dashboardInitFetching = actionCreatorFactory('DASHBOARD_INIT_FETCHING').create();
2323

24-
export const dashboardInitServices = noPayloadActionCreatorFactory('DASHBOARD_INIT_SERVICES').create();
24+
export const dashboardInitServices = actionCreatorFactory('DASHBOARD_INIT_SERVICES').create();
2525

26-
export const dashboardInitSlow = noPayloadActionCreatorFactory('SET_DASHBOARD_INIT_SLOW').create();
26+
export const dashboardInitSlow = actionCreatorFactory('SET_DASHBOARD_INIT_SLOW').create();
2727

2828
export const dashboardInitCompleted = actionCreatorFactory<MutableDashboard>('DASHBOARD_INIT_COMLETED').create();
2929

@@ -35,7 +35,7 @@ export const dashboardInitFailed = actionCreatorFactory<DashboardInitError>('DAS
3535
/*
3636
* When leaving dashboard, resets state
3737
* */
38-
export const cleanUpDashboard = noPayloadActionCreatorFactory('DASHBOARD_CLEAN_UP').create();
38+
export const cleanUpDashboard = actionCreatorFactory('DASHBOARD_CLEAN_UP').create();
3939

4040
export function getDashboardPermissions(id: number): ThunkResult<void> {
4141
return async dispatch => {

public/app/features/datasources/state/actions.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { DataSourceSettings, DataSourcePluginMeta } from '@grafana/ui';
99
import { StoreState } from 'app/types';
1010
import { LocationUpdate } from '@grafana/runtime';
1111
import { actionCreatorFactory } from 'app/core/redux';
12-
import { ActionOf, noPayloadActionCreatorFactory } from 'app/core/redux/actionCreatorFactory';
12+
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
1313
import { getPluginSettings } from 'app/features/plugins/PluginSettingsCache';
1414
import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader';
1515

@@ -19,7 +19,7 @@ export const dataSourcesLoaded = actionCreatorFactory<DataSourceSettings[]>('LOA
1919

2020
export const dataSourceMetaLoaded = actionCreatorFactory<DataSourcePluginMeta>('LOAD_DATA_SOURCE_META').create();
2121

22-
export const dataSourceTypesLoad = noPayloadActionCreatorFactory('LOAD_DATA_SOURCE_TYPES').create();
22+
export const dataSourceTypesLoad = actionCreatorFactory('LOAD_DATA_SOURCE_TYPES').create();
2323

2424
export const dataSourceTypesLoaded = actionCreatorFactory<DataSourcePluginMeta[]>('LOADED_DATA_SOURCE_TYPES').create();
2525

style_guides/redux.md

-25
Original file line numberDiff line numberDiff line change
@@ -43,31 +43,6 @@ export const someAction = actionCreatorFactory<string>('SOME_ACTION').create();
4343
export const theAction = actionCreatorFactory<string>('SOME_ACTION').create(); // will throw
4444
```
4545
46-
### noPayloadActionCreatorFactory
47-
48-
Used when you don't need to supply a payload for your action. Will create an action creator with the following signature
49-
50-
```typescript
51-
{ type: string , (): {type: string; payload: undefined;} }
52-
```
53-
54-
where the `type` string will be ensured to be unique.
55-
56-
#### Example
57-
58-
```typescript
59-
export const noPayloadAction = noPayloadActionCreatorFactory('NO_PAYLOAD').create();
60-
61-
// later when dispatched
62-
noPayloadAction();
63-
```
64-
65-
```typescript
66-
// declaring an action creator with a type string that has already been defined will throw
67-
export const noPayloadAction = noPayloadActionCreatorFactory('NO_PAYLOAD').create();
68-
export const noAction = noPayloadActionCreatorFactory('NO_PAYLOAD').create(); // will throw
69-
```
70-
7146
### reducerFactory
7247
7348
Fluent API used to create a reducer. (same as implementing the standard switch statement in Redux)

0 commit comments

Comments
 (0)