@mic-rexjs/usecases-react 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +1 -1
- package/es/components/UseCaseFragment/index.d.ts +2 -2
- package/es/components/UseCaseFragment/types.d.ts +3 -3
- package/es/configs/defaultUseCaseContext/index.d.ts +2 -3
- package/es/configs/defaultUseCaseContext/types.d.ts +13 -12
- package/es/configs/useCaseContextReferenceMap/index.d.ts +1 -0
- package/es/configs/useCaseContextReferenceMap/index.js +1 -0
- package/es/configs/useCaseContextReferenceMap/types.d.ts +8 -0
- package/es/enums/UseCaseArgumentTypes/index.d.ts +5 -0
- package/es/enums/UseCaseArgumentTypes/index.js +6 -0
- package/es/enums/UseCaseStatuses/index.d.ts +10 -0
- package/es/enums/UseCaseStatuses/index.js +18 -0
- package/es/hooks/useArgumentTypes/index.d.ts +3 -0
- package/es/hooks/useArgumentTypes/index.js +19 -0
- package/es/hooks/useContextualItem/index.d.ts +3 -0
- package/es/hooks/useContextualItem/index.js +13 -0
- package/es/hooks/useContextualItem/types.d.ts +3 -0
- package/es/hooks/useEntity/index.d.ts +4 -0
- package/es/hooks/useEntity/index.js +49 -0
- package/es/hooks/useGlobalUseCase/index.js +3 -8
- package/es/hooks/useGlobalUseCase/index.test.js +10 -30
- package/es/hooks/useGlobalUseCase/types.d.ts +7 -10
- package/es/hooks/useMemoizedCall/index.d.ts +2 -0
- package/es/hooks/useMemoizedCall/index.js +15 -0
- package/es/hooks/useProvider/index.d.ts +4 -4
- package/es/hooks/useProvider/index.js +22 -15
- package/es/hooks/useStatelessUseCase/index.js +2 -5
- package/es/hooks/useStatelessUseCase/index.test.js +4 -42
- package/es/hooks/useStatelessUseCase/types.d.ts +2 -4
- package/es/hooks/useUseCase/index.js +44 -74
- package/es/hooks/useUseCase/index.test.js +26 -1
- package/es/hooks/useUseCase/types.d.ts +32 -45
- package/es/hooks/useUseCaseContext/index.d.ts +5 -3
- package/es/hooks/useUseCaseContext/index.js +44 -8
- package/es/hooks/useUseCaseContext/index.test.js +87 -0
- package/es/hooks/useUseCaseStatuses/index.d.ts +6 -0
- package/es/hooks/useUseCaseStatuses/index.js +29 -0
- package/es/index.d.ts +1 -1
- package/es/methods/cacheCall/index.d.ts +2 -0
- package/es/methods/cacheCall/index.js +26 -0
- package/es/methods/cacheCall/types.d.ts +13 -0
- package/es/methods/cacheCall/types.js +1 -0
- package/es/methods/cacheCalls/index.d.ts +2 -0
- package/es/methods/cacheCalls/index.js +8 -0
- package/es/methods/fillArguments/index.d.ts +5 -0
- package/es/methods/fillArguments/index.js +41 -0
- package/es/methods/fillArguments/types.d.ts +10 -0
- package/es/methods/fillArguments/types.js +1 -0
- package/es/methods/getRenderingEntity/index.d.ts +3 -0
- package/es/methods/getRenderingEntity/index.js +13 -0
- package/es/methods/initEntityReducers/index.d.ts +2 -3
- package/es/methods/initEntityReducers/index.js +3 -5
- package/es/methods/transformGlobalArguments/index.d.ts +3 -0
- package/es/methods/transformGlobalArguments/index.js +8 -0
- package/es/methods/transformGlobalArguments/types.d.ts +2 -0
- package/es/methods/transformGlobalArguments/types.js +1 -0
- package/es/methods/triggerCallbacks/index.d.ts +1 -1
- package/es/methods/triggerCallbacks/index.js +3 -3
- package/lib/configs/useCaseContextReferenceMap/index.js +8 -0
- package/lib/enums/UseCaseArgumentTypes/index.js +13 -0
- package/lib/enums/UseCaseStatuses/index.js +25 -0
- package/lib/hooks/useArgumentTypes/index.js +31 -0
- package/lib/hooks/useContextualItem/index.js +21 -0
- package/lib/hooks/useEntity/index.js +63 -0
- package/lib/hooks/useGlobalUseCase/index.js +3 -10
- package/lib/hooks/useGlobalUseCase/index.test.js +8 -35
- package/lib/hooks/useMemoizedCall/index.js +22 -0
- package/lib/hooks/useProvider/index.js +24 -15
- package/lib/hooks/useStatelessUseCase/index.js +2 -12
- package/lib/hooks/useStatelessUseCase/index.test.js +2 -43
- package/lib/hooks/useUseCase/index.js +55 -82
- package/lib/hooks/useUseCase/index.test.js +56 -25
- package/lib/hooks/useUseCaseContext/index.js +48 -8
- package/lib/hooks/useUseCaseContext/index.test.js +101 -0
- package/lib/hooks/useUseCaseStatuses/index.js +36 -0
- package/lib/methods/cacheCall/index.js +42 -0
- package/lib/methods/cacheCalls/index.js +20 -0
- package/lib/methods/fillArguments/index.js +31 -0
- package/lib/methods/fillArguments/types.js +5 -0
- package/lib/methods/getRenderingEntity/index.js +20 -0
- package/lib/methods/initEntityReducers/index.js +2 -5
- package/lib/methods/transformGlobalArguments/index.js +21 -0
- package/lib/methods/transformGlobalArguments/types.js +5 -0
- package/lib/methods/triggerCallbacks/index.js +3 -3
- package/package.json +3 -3
- package/es/configs/usecaseContextMap/index.d.ts +0 -1
- package/es/configs/usecaseContextMap/index.js +0 -1
- package/es/configs/usecaseContextMap/types.d.ts +0 -4
- package/es/hooks/useChangeCallbackCollection/index.d.ts +0 -3
- package/es/hooks/useChangeCallbackCollection/index.js +0 -29
- package/es/methods/cacheReducerCalls/index.d.ts +0 -3
- package/es/methods/cacheReducerCalls/index.js +0 -26
- package/es/methods/cacheReducerCalls/types.d.ts +0 -11
- package/es/methods/getRootEntity/index.d.ts +0 -3
- package/es/methods/getRootEntity/index.js +0 -10
- package/es/methods/initEntityReducers/types.d.ts +0 -3
- package/es/methods/removeItem/index.d.ts +0 -1
- package/es/methods/removeItem/index.js +0 -7
- package/es/methods/toMaxArguments/index.d.ts +0 -3
- package/es/methods/toMaxArguments/index.js +0 -28
- package/lib/configs/usecaseContextMap/index.js +0 -8
- package/lib/hooks/useChangeCallbackCollection/index.js +0 -37
- package/lib/methods/cacheReducerCalls/index.js +0 -45
- package/lib/methods/getRootEntity/index.js +0 -17
- package/lib/methods/removeItem/index.js +0 -14
- package/lib/methods/toMaxArguments/index.js +0 -25
- /package/es/configs/{usecaseContextMap → useCaseContextReferenceMap}/types.js +0 -0
- /package/es/{methods/cacheReducerCalls → hooks/useContextualItem}/types.js +0 -0
- /package/es/{methods/initEntityReducers/types.js → hooks/useUseCaseContext/index.test.d.ts} +0 -0
- /package/lib/configs/{usecaseContextMap → useCaseContextReferenceMap}/types.js +0 -0
- /package/lib/{methods/cacheReducerCalls → hooks/useContextualItem}/types.js +0 -0
- /package/lib/methods/{initEntityReducers → cacheCall}/types.js +0 -0
|
@@ -1,88 +1,58 @@
|
|
|
1
|
-
import { useCreation
|
|
2
|
-
import { useContext
|
|
1
|
+
import { useCreation } from 'ahooks';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
3
|
import { useConstant } from '../useConstant';
|
|
4
4
|
import { useConstantFn } from '../useConstantFn';
|
|
5
5
|
import { useProvider } from '../useProvider';
|
|
6
|
-
import { useCompareDeps } from '../useCompareDeps';
|
|
7
6
|
import { initEntityReducers } from '../../methods/initEntityReducers';
|
|
8
|
-
import { triggerCallbacks } from '../../methods/triggerCallbacks';
|
|
9
|
-
import { getRootEntity } from '../../methods/getRootEntity';
|
|
10
7
|
import { useUseCaseContext } from '../useUseCaseContext';
|
|
11
|
-
import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
|
|
12
8
|
import { useIsRenderingRef } from '../useIsRenderingRef';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
9
|
+
import { fillArguments } from '../../methods/fillArguments';
|
|
10
|
+
import { useArgumentTypes } from '../useArgumentTypes';
|
|
11
|
+
import { useUseCaseStatuses } from '../useUseCaseStatuses';
|
|
12
|
+
import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
|
|
13
|
+
import { useEntity } from '../useEntity';
|
|
14
|
+
import { useContextualItem } from '../useContextualItem';
|
|
15
|
+
import { cacheCalls } from '../../methods/cacheCalls';
|
|
17
16
|
export const useUseCase = ((...args) => {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
17
|
+
const argumentTypes = useArgumentTypes(args);
|
|
18
|
+
const fullArguments = fillArguments(args, argumentTypes);
|
|
19
|
+
const [unsafeEntity, unsafeUsecase, unsafeMode, options, deps] = fullArguments;
|
|
20
|
+
const unkownUsecase = useConstantFn(unsafeUsecase);
|
|
21
|
+
const usecase = unkownUsecase;
|
|
22
|
+
const entityUseCase = unkownUsecase;
|
|
24
23
|
const isRenderingRef = useIsRenderingRef();
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const {
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const entity = useCreation(() => {
|
|
37
|
-
if (!isContextRoot) {
|
|
38
|
-
return contextEntity;
|
|
39
|
-
}
|
|
40
|
-
return getRootEntity(entityState, unsafeEntity, mode);
|
|
41
|
-
}, [isContextRoot, contextEntity, mode, entityState, unsafeEntity]);
|
|
42
|
-
const onEntityChange = useMemoizedFn((newEntity, oldEntity) => {
|
|
43
|
-
if ((mode & UseCaseModes.Stateless) !== UseCaseModes.Stateless) {
|
|
44
|
-
setEntityState(newEntity);
|
|
24
|
+
const mode = useConstant(unsafeMode);
|
|
25
|
+
const context = useUseCaseContext(unkownUsecase, argumentTypes, mode);
|
|
26
|
+
const contextValue = useContext(context)?.() || null;
|
|
27
|
+
const entityContextValue = contextValue;
|
|
28
|
+
const statuses = useUseCaseStatuses(argumentTypes, mode, contextValue);
|
|
29
|
+
const { reducers: contextReducers = null } = contextValue || {};
|
|
30
|
+
const { store: contextStore = null } = entityContextValue || {};
|
|
31
|
+
const [entity, store] = useEntity(statuses, unsafeEntity, contextStore, options);
|
|
32
|
+
const reducers = useContextualItem(statuses, contextReducers, () => {
|
|
33
|
+
if ((statuses & UseCaseStatuses.EntityEnabled) !== UseCaseStatuses.EntityEnabled) {
|
|
34
|
+
return usecase(options);
|
|
45
35
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return usecase(options);
|
|
54
|
-
});
|
|
55
|
-
const rootEntityReducers = useCreation(() => {
|
|
56
|
-
void depsKey;
|
|
57
|
-
if (!isContextRoot) {
|
|
58
|
-
return null;
|
|
36
|
+
const hookOptions = options;
|
|
37
|
+
return initEntityReducers(entityUseCase, store, hookOptions);
|
|
38
|
+
}, deps);
|
|
39
|
+
const Provider = useProvider(statuses, context, store, reducers);
|
|
40
|
+
return useCreation(() => {
|
|
41
|
+
if ((statuses & UseCaseStatuses.ContextEnabled) !== UseCaseStatuses.ContextEnabled) {
|
|
42
|
+
return reducers;
|
|
59
43
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return rootEntityReducers || contextEntityReducers || {};
|
|
64
|
-
}, [rootEntityReducers, contextEntityReducers]);
|
|
65
|
-
const reducers = useCreation(() => {
|
|
66
|
-
void depsKey;
|
|
67
|
-
if (isContextMode) {
|
|
68
|
-
return {};
|
|
44
|
+
const rootEnabled = (statuses & UseCaseStatuses.RootEnabled) === UseCaseStatuses.RootEnabled;
|
|
45
|
+
if ((statuses & UseCaseStatuses.EntityEnabled) !== UseCaseStatuses.EntityEnabled) {
|
|
46
|
+
return rootEnabled ? [reducers, Provider] : reducers;
|
|
69
47
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const Provider = useProvider(context, mode, entity, entityReducers, changeCallbackCollection);
|
|
73
|
-
const createCoreCollection = useMemoizedFn((coreEntity, coreReducers) => {
|
|
74
|
-
return [
|
|
75
|
-
coreEntity,
|
|
76
|
-
cacheReducerCalls(coreReducers, () => {
|
|
48
|
+
const cachedReducers = cacheCalls(reducers, {
|
|
49
|
+
onShouldCache() {
|
|
77
50
|
return isRenderingRef.current;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return useCreation(() => {
|
|
83
|
-
if (isContextMode) {
|
|
84
|
-
return createCoreCollection(entity, entityReducers);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
if (rootEnabled) {
|
|
54
|
+
return [entity, cachedReducers, Provider];
|
|
85
55
|
}
|
|
86
|
-
return
|
|
87
|
-
}, [
|
|
56
|
+
return [entity, cachedReducers];
|
|
57
|
+
}, [statuses, entity, reducers, Provider, isRenderingRef]);
|
|
88
58
|
});
|
|
@@ -86,7 +86,7 @@ const Child = ({ textPrefix = '', onUpdate, onPathChange, onUndefinedEntity }) =
|
|
|
86
86
|
useUpdateEffect(pathChange, [path, pathChange]);
|
|
87
87
|
return (_jsxs("div", { children: [_jsxs("main", { children: ["child path: ", path, _jsx("br", {}), "child ext: ", ext] }), _jsx("footer", { children: _jsx("button", { onClick: onClick, children: textPrefix + CHILD_BUTTON_TEXT }) })] }));
|
|
88
88
|
};
|
|
89
|
-
const Parent = ({ children, mode, onUpdate, onSetPath }) => {
|
|
89
|
+
const Parent = ({ children, mode = UseCaseModes.Normal, onUpdate, onSetPath }) => {
|
|
90
90
|
const [{ path, ext }, { setPath }, Provider] = useUseCase(defaultFile, fileUseCase, mode);
|
|
91
91
|
const onClick = () => {
|
|
92
92
|
setPath(onSetPath?.() || '');
|
|
@@ -1403,6 +1403,31 @@ describe('useUseCase', () => {
|
|
|
1403
1403
|
expect(onChangeC).toHaveReturnedWith(3);
|
|
1404
1404
|
});
|
|
1405
1405
|
});
|
|
1406
|
+
describe('`useUseCase` should work the same as `usePseudoCoreCollection`', () => {
|
|
1407
|
+
test('the return value should be `PseudoCoreCollection`', () => {
|
|
1408
|
+
const { result } = renderHook(() => {
|
|
1409
|
+
return useUseCase(mathUseCase, UseCaseModes.Global);
|
|
1410
|
+
});
|
|
1411
|
+
const { current } = result;
|
|
1412
|
+
expect(current).toEqual([expect.any(Object), expect.any(Function)]);
|
|
1413
|
+
});
|
|
1414
|
+
test('the return value should be `reducers` object at child component', () => {
|
|
1415
|
+
const onMountA = jest.fn();
|
|
1416
|
+
const A = () => {
|
|
1417
|
+
const reducers = useUseCase(mathUseCase);
|
|
1418
|
+
useMount(() => {
|
|
1419
|
+
onMountA(reducers);
|
|
1420
|
+
});
|
|
1421
|
+
return null;
|
|
1422
|
+
};
|
|
1423
|
+
const B = () => {
|
|
1424
|
+
const [, Provider] = useUseCase(mathUseCase, UseCaseModes.Global);
|
|
1425
|
+
return (_jsx(Provider, { children: _jsx(A, {}) }));
|
|
1426
|
+
};
|
|
1427
|
+
render(_jsx(B, {}));
|
|
1428
|
+
expect(onMountA).toHaveBeenCalledWith(expect.any(Object));
|
|
1429
|
+
});
|
|
1430
|
+
});
|
|
1406
1431
|
describe('`useUseCase` should work the same as `useReducers`', () => {
|
|
1407
1432
|
test('`entity` should equal `defaultFile`', () => {
|
|
1408
1433
|
const { result } = renderHook(() => {
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { EntityReducers, EntityUseCase, Reducers, UseCase } from '@mic-rexjs/usecases';
|
|
1
|
+
import { EntityReducerMap, EntityReducers, EntityUseCase, ReducerMap, Reducers, UseCase } from '@mic-rexjs/usecases';
|
|
3
2
|
import { UseCaseProvider } from '../useProvider/types';
|
|
4
3
|
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
5
|
-
|
|
4
|
+
import { ContextualEntityReducers } from '../../configs/defaultUseCaseContext/types';
|
|
5
|
+
export type RootCoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = [
|
|
6
|
+
entity: T,
|
|
7
|
+
reducers: ContextualEntityReducers<T, TEntityReducers>,
|
|
8
|
+
Provider: UseCaseProvider
|
|
9
|
+
];
|
|
10
|
+
export type ContextualCoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = [
|
|
11
|
+
entity: T,
|
|
12
|
+
reducers: ContextualEntityReducers<T, TEntityReducers>
|
|
13
|
+
];
|
|
14
|
+
export type CoreCollection<T, TEntityReducers extends EntityReducerMap<T>> = RootCoreCollection<T, TEntityReducers> | ContextualCoreCollection<T, TEntityReducers>;
|
|
15
|
+
export type PseudoCoreCollection<T extends ReducerMap, TProvider extends UseCaseProvider | null = UseCaseProvider> = [
|
|
16
|
+
reducers: T,
|
|
17
|
+
Provider: TProvider
|
|
18
|
+
];
|
|
6
19
|
export interface EntityGetter<T> {
|
|
7
20
|
(): T;
|
|
8
21
|
}
|
|
@@ -32,67 +45,41 @@ export interface UseCaseHookOwnOptions<T, TUseCaseOptions extends object> extend
|
|
|
32
45
|
options?: TUseCaseOptions;
|
|
33
46
|
}
|
|
34
47
|
export type UseCaseHookOptions<T, TUseCaseOptions extends object = object> = TUseCaseOptions & UseCaseHookOwnOptions<T, TUseCaseOptions>;
|
|
35
|
-
export
|
|
36
|
-
usecase: EntityUseCase<T, TEntityReducers> &
|
|
48
|
+
export interface ContextualCoreCollectionHook {
|
|
49
|
+
<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
|
|
37
50
|
/**
|
|
38
51
|
* 如果不使用 `&`,那么很多情况下 `options` 类型无法被正确推导;
|
|
39
52
|
* 因为使用 `&` 是为了让该参数 `usecase` 的泛型 `T` 推导占优先级,
|
|
40
53
|
* 从而保证 `options` 里的泛型 `T` 是根据 `usecase` 来推导的。
|
|
41
54
|
*/
|
|
42
|
-
UseCase<
|
|
43
|
-
options?: UseCaseHookContextualOptions<T>
|
|
44
|
-
];
|
|
45
|
-
export interface ContextualCoreCollectionHook {
|
|
46
|
-
<T, TEntityReducers extends EntityReducers<T>>(...args: ContextualCoreCollectionHookParameters<T, TEntityReducers>): CoreCollection<T, TEntityReducers, null>;
|
|
55
|
+
UseCase<EntityReducerMap<T>, TUseCaseOptions>, options?: UseCaseHookContextualOptions<T>): ContextualCoreCollection<T, TEntityReducers>;
|
|
47
56
|
}
|
|
48
|
-
export
|
|
49
|
-
entity: T | EntityGetter<T>,
|
|
50
|
-
usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
|
|
57
|
+
export interface RootCoreCollectionHook {
|
|
58
|
+
<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(entity: T | EntityGetter<T>, usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
|
|
51
59
|
/**
|
|
52
60
|
* 如果不使用 `&`,那么很多情况下 `options` 类型无法被正确推导;
|
|
53
61
|
* 因为使用 `&` 是为了让该参数 `usecase` 的泛型 `T` 推导占优先级,
|
|
54
62
|
* 从而保证 `options` 里的泛型 `T` 是根据 `usecase` 来推导的。
|
|
55
63
|
*/
|
|
56
|
-
UseCase<
|
|
57
|
-
options?: UseCaseHookOptions<T, TUseCaseOptions>,
|
|
58
|
-
deps?: unknown[]
|
|
59
|
-
];
|
|
60
|
-
export interface RootCoreCollectionHook {
|
|
61
|
-
<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(...args: RootCoreCollectionHookParameters<T, TEntityReducers, TUseCaseOptions>): CoreCollection<T, TEntityReducers>;
|
|
64
|
+
UseCase<EntityReducerMap<T>, TUseCaseOptions>, options?: UseCaseHookOptions<T, TUseCaseOptions>, deps?: unknown[]): RootCoreCollection<T, TEntityReducers>;
|
|
62
65
|
}
|
|
63
|
-
export
|
|
64
|
-
entity: T | EntityGetter<T>,
|
|
65
|
-
usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
|
|
66
|
+
export interface ModeCoreCollectionHook {
|
|
67
|
+
<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(entity: T | EntityGetter<T>, usecase: EntityUseCase<T, TEntityReducers, TUseCaseOptions> &
|
|
66
68
|
/**
|
|
67
69
|
* 如果不使用 `&`,那么很多情况下 `options` 类型无法被正确推导;
|
|
68
70
|
* 因为使用 `&` 是为了让该参数 `usecase` 的泛型 `T` 推导占优先级,
|
|
69
71
|
* 从而保证 `options` 里的泛型 `T` 是根据 `usecase` 来推导的。
|
|
70
72
|
*/
|
|
71
|
-
UseCase<
|
|
72
|
-
mode?: UseCaseModes,
|
|
73
|
-
options?: UseCaseHookOptions<T, TUseCaseOptions>,
|
|
74
|
-
deps?: unknown[]
|
|
75
|
-
];
|
|
76
|
-
export interface ModeCoreCollectionHook {
|
|
77
|
-
<T, TEntityReducers extends EntityReducers<T>, TUseCaseOptions extends object = object>(...args: ModeCoreCollectionHookParameters<T, TEntityReducers, TUseCaseOptions>): CoreCollection<T, TEntityReducers>;
|
|
73
|
+
UseCase<EntityReducerMap<T>, TUseCaseOptions>, mode: UseCaseModes, options?: UseCaseHookOptions<T, TUseCaseOptions>, deps?: unknown[]): RootCoreCollection<T, TEntityReducers>;
|
|
78
74
|
}
|
|
79
|
-
export interface
|
|
75
|
+
export interface PseudoCoreCollectionHook {
|
|
76
|
+
<T extends Reducers, TUseCaseOptions extends object = object>(usecase: UseCase<T, TUseCaseOptions>, mode: UseCaseModes, options?: TUseCaseOptions, deps?: unknown[]): PseudoCoreCollection<T>;
|
|
80
77
|
}
|
|
81
|
-
export type ReducersHookParameters<T extends Reducers, TUseCaseOptions extends object = object> = [
|
|
82
|
-
usecase: UseCase<T, TUseCaseOptions>,
|
|
83
|
-
options?: TUseCaseOptions,
|
|
84
|
-
deps?: unknown[]
|
|
85
|
-
];
|
|
86
78
|
export interface ReducersHook {
|
|
87
|
-
<T extends Reducers, TUseCaseOptions extends object = object>(
|
|
79
|
+
<T extends Reducers, TUseCaseOptions extends object = object>(usecase: UseCase<T, TUseCaseOptions>, options?: TUseCaseOptions, deps?: unknown[]): T;
|
|
88
80
|
}
|
|
89
|
-
export
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
mode: UseCaseModes,
|
|
94
|
-
options: TUseCaseOptions | UseCaseHookOptions<T, TUseCaseOptions> | UseCaseHookContextualOptions<T>,
|
|
95
|
-
deps: unknown[]
|
|
96
|
-
];
|
|
97
|
-
export interface UseCaseHook extends CoreCollectionHook, ReducersHook {
|
|
81
|
+
export interface CoreCollectionHook extends ContextualCoreCollectionHook, RootCoreCollectionHook, ModeCoreCollectionHook {
|
|
82
|
+
}
|
|
83
|
+
export type UseCaseHookParameters = Parameters<ContextualCoreCollectionHook> | Parameters<RootCoreCollectionHook> | Parameters<ModeCoreCollectionHook> | Parameters<PseudoCoreCollectionHook> | Parameters<ReducersHook>;
|
|
84
|
+
export interface UseCaseHook extends CoreCollectionHook, PseudoCoreCollectionHook, ReducersHook {
|
|
98
85
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { UseCaseContext } from '../../configs/defaultUseCaseContext/types';
|
|
3
|
-
|
|
1
|
+
import { ReducerMap, UseCase } from '@mic-rexjs/usecases';
|
|
2
|
+
import { UseCaseContext, UseCaseContextValue } from '../../configs/defaultUseCaseContext/types';
|
|
3
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
4
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
5
|
+
export declare const useUseCaseContext: <T extends ReducerMap<import("@mic-rexjs/usecases").Reducer<unknown>>, TUseCaseOptions extends object, TContext extends UseCaseContext<UseCaseContextValue<T>>>(usecase: UseCase<T, TUseCaseOptions>, argumentTypes?: UseCaseArgumentTypes, mode?: UseCaseModes) => TContext;
|
|
@@ -1,17 +1,53 @@
|
|
|
1
1
|
import { useConstant } from '../useConstant';
|
|
2
|
-
import {
|
|
2
|
+
import { usecaseContextReferenceMap } from '../../configs/useCaseContextReferenceMap';
|
|
3
3
|
import { createContext } from 'react';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { useUnmount } from 'ahooks';
|
|
5
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
6
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
7
|
+
import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
|
|
8
|
+
export const useUseCaseContext = (usecase, argumentTypes = UseCaseArgumentTypes.None, mode = UseCaseModes.Normal) => {
|
|
9
|
+
const map = usecaseContextReferenceMap;
|
|
10
|
+
const context = useConstant(() => {
|
|
7
11
|
if (map.has(usecase)) {
|
|
8
|
-
|
|
12
|
+
const reference = map.get(usecase);
|
|
13
|
+
const { value, times } = reference;
|
|
14
|
+
map.set(usecase, {
|
|
15
|
+
value,
|
|
16
|
+
times: times + 1,
|
|
17
|
+
});
|
|
18
|
+
return value;
|
|
9
19
|
}
|
|
10
|
-
|
|
11
|
-
|
|
20
|
+
switch (true) {
|
|
21
|
+
case (mode & UseCaseModes.Global) === UseCaseModes.Global:
|
|
22
|
+
case (argumentTypes & UseCaseArgumentTypes.Entity) === UseCaseArgumentTypes.Entity:
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
return defaultUseCaseContext;
|
|
12
26
|
}
|
|
13
27
|
const ctx = createContext(null);
|
|
14
|
-
map.set(usecase,
|
|
28
|
+
map.set(usecase, {
|
|
29
|
+
value: ctx,
|
|
30
|
+
times: 1,
|
|
31
|
+
});
|
|
15
32
|
return ctx;
|
|
16
33
|
});
|
|
34
|
+
useUnmount(() => {
|
|
35
|
+
if (!map.has(usecase)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const reference = map.get(usecase);
|
|
39
|
+
const { value, times } = reference;
|
|
40
|
+
if (context !== value) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (times === 1) {
|
|
44
|
+
map.delete(usecase);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
map.set(usecase, {
|
|
48
|
+
value,
|
|
49
|
+
times: times - 1,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return context;
|
|
17
53
|
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, expect, test } from '@jest/globals';
|
|
2
|
+
import { renderHook } from '@testing-library/react';
|
|
3
|
+
import { useUseCaseContext } from '.';
|
|
4
|
+
import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
|
|
5
|
+
import { usecaseContextReferenceMap } from '../../configs/useCaseContextReferenceMap';
|
|
6
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
7
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
8
|
+
const testUseCase = () => {
|
|
9
|
+
return {};
|
|
10
|
+
};
|
|
11
|
+
describe('useUseCaseContext', () => {
|
|
12
|
+
test('should return the default context if map has not saved a usecase with default args', () => {
|
|
13
|
+
const { result } = renderHook(() => {
|
|
14
|
+
return useUseCaseContext(testUseCase);
|
|
15
|
+
});
|
|
16
|
+
const { current } = result;
|
|
17
|
+
expect(current).toBe(defaultUseCaseContext);
|
|
18
|
+
});
|
|
19
|
+
test('should return the default context if map has not saved a usecase with `UseCaseArgumentTypes.None` & `UseCaseModes.Normal`', () => {
|
|
20
|
+
const { result } = renderHook(() => {
|
|
21
|
+
return useUseCaseContext(testUseCase, UseCaseArgumentTypes.None, UseCaseModes.Normal);
|
|
22
|
+
});
|
|
23
|
+
const { current } = result;
|
|
24
|
+
expect(current).toBe(defaultUseCaseContext);
|
|
25
|
+
});
|
|
26
|
+
test('should return a new context if map has not saved a usecase with `UseCaseArgumentTypes.Entity` & `UseCaseModes.Normal`', () => {
|
|
27
|
+
const { result } = renderHook(() => {
|
|
28
|
+
return useUseCaseContext(testUseCase, UseCaseArgumentTypes.Entity, UseCaseModes.Normal);
|
|
29
|
+
});
|
|
30
|
+
const { current } = result;
|
|
31
|
+
expect(typeof current).toBe('object');
|
|
32
|
+
});
|
|
33
|
+
test('should return a new context if map has not saved a usecase with `UseCaseArgumentTypes.None` & `UseCaseModes.Global`', () => {
|
|
34
|
+
const { result } = renderHook(() => {
|
|
35
|
+
return useUseCaseContext(testUseCase, UseCaseArgumentTypes.None, UseCaseModes.Global);
|
|
36
|
+
});
|
|
37
|
+
const { current } = result;
|
|
38
|
+
expect(typeof current).toBe('object');
|
|
39
|
+
});
|
|
40
|
+
test.each([
|
|
41
|
+
{
|
|
42
|
+
type: UseCaseArgumentTypes.Entity,
|
|
43
|
+
mode: UseCaseModes.Normal,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: UseCaseArgumentTypes.None,
|
|
47
|
+
mode: UseCaseModes.Global,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: UseCaseArgumentTypes.Entity,
|
|
51
|
+
mode: UseCaseModes.Global,
|
|
52
|
+
},
|
|
53
|
+
])('should return the existing context if map has save a usecase already', ({ type, mode }) => {
|
|
54
|
+
const { result } = renderHook(() => {
|
|
55
|
+
return useUseCaseContext(testUseCase, type, mode) === useUseCaseContext(testUseCase);
|
|
56
|
+
});
|
|
57
|
+
const { current: isSame } = result;
|
|
58
|
+
expect(isSame).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
test('check context reference times when mount/unmount a usecase', () => {
|
|
61
|
+
const { unmount: unmount1 } = renderHook(() => {
|
|
62
|
+
useUseCaseContext(testUseCase, UseCaseArgumentTypes.Entity);
|
|
63
|
+
});
|
|
64
|
+
const { times: times1 } = usecaseContextReferenceMap.get(testUseCase);
|
|
65
|
+
const { unmount: unmount2 } = renderHook(() => {
|
|
66
|
+
useUseCaseContext(testUseCase);
|
|
67
|
+
useUseCaseContext(testUseCase);
|
|
68
|
+
});
|
|
69
|
+
const { times: times2 } = usecaseContextReferenceMap.get(testUseCase);
|
|
70
|
+
expect(times1).toBe(1);
|
|
71
|
+
expect(times2).toBe(3);
|
|
72
|
+
unmount1();
|
|
73
|
+
const { times: times3 } = usecaseContextReferenceMap.get(testUseCase);
|
|
74
|
+
expect(times3).toBe(2);
|
|
75
|
+
unmount2();
|
|
76
|
+
const hasSaved = usecaseContextReferenceMap.has(testUseCase);
|
|
77
|
+
expect(hasSaved).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
test('context reference times should not change when rerender hooks', () => {
|
|
80
|
+
const { rerender } = renderHook(() => {
|
|
81
|
+
useUseCaseContext(testUseCase, UseCaseArgumentTypes.Entity);
|
|
82
|
+
});
|
|
83
|
+
rerender();
|
|
84
|
+
const { times } = usecaseContextReferenceMap.get(testUseCase);
|
|
85
|
+
expect(times).toBe(1);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { UseCaseContextValue } from '../../configs/defaultUseCaseContext/types';
|
|
2
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
3
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
4
|
+
import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
|
|
5
|
+
import { ReducerMap } from '@mic-rexjs/usecases';
|
|
6
|
+
export declare const useUseCaseStatuses: <T, TReducers extends ReducerMap<import("@mic-rexjs/usecases").Reducer<unknown>>>(argumentTypes: UseCaseArgumentTypes, mode: UseCaseModes, contextValue: UseCaseContextValue<TReducers> | null) => UseCaseStatuses;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
2
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
3
|
+
import { UseCaseStatuses } from '../../enums/UseCaseStatuses';
|
|
4
|
+
import { useCreation } from 'ahooks';
|
|
5
|
+
export const useUseCaseStatuses = (argumentTypes, mode, contextValue) => {
|
|
6
|
+
return useCreation(() => {
|
|
7
|
+
let statuses = UseCaseStatuses.None;
|
|
8
|
+
const { store } = (contextValue || {});
|
|
9
|
+
if ((argumentTypes & UseCaseArgumentTypes.Entity) === UseCaseArgumentTypes.Entity) {
|
|
10
|
+
statuses |= UseCaseStatuses.EntityRootEnabled;
|
|
11
|
+
}
|
|
12
|
+
if (contextValue === null) {
|
|
13
|
+
statuses |= UseCaseStatuses.RootEnabled;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
statuses |= UseCaseStatuses.ContextEnabled;
|
|
17
|
+
}
|
|
18
|
+
if (store) {
|
|
19
|
+
statuses |= UseCaseStatuses.EntityEnabled;
|
|
20
|
+
}
|
|
21
|
+
if ((mode & UseCaseModes.Stateless) === UseCaseModes.Stateless) {
|
|
22
|
+
statuses |= UseCaseStatuses.StatelessEnabled;
|
|
23
|
+
}
|
|
24
|
+
if ((mode & UseCaseModes.Global) === UseCaseModes.Global) {
|
|
25
|
+
statuses |= UseCaseStatuses.GlobalEnabled;
|
|
26
|
+
}
|
|
27
|
+
return statuses;
|
|
28
|
+
}, [argumentTypes, contextValue, mode]);
|
|
29
|
+
};
|
package/es/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { UseCaseFragment } from './components/UseCaseFragment';
|
|
|
2
2
|
export { useUseCase } from './hooks/useUseCase';
|
|
3
3
|
export { useGlobalUseCase } from './hooks/useGlobalUseCase';
|
|
4
4
|
export { useStatelessUseCase } from './hooks/useStatelessUseCase';
|
|
5
|
-
export type { CoreCollection } from './hooks/useUseCase/types';
|
|
5
|
+
export type { RootCoreCollection, ContextualCoreCollection, CoreCollection, PseudoCoreCollection, } from './hooks/useUseCase/types';
|
|
6
6
|
export type { UseCaseHookOptions } from './hooks/useUseCase/types';
|
|
7
7
|
export type { UseCaseProvider } from './hooks/useProvider/types';
|
|
8
8
|
export type { UseCaseFragmentProps } from './components/UseCaseFragment/types';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { isSameArray } from '../isSameArray';
|
|
2
|
+
export const cacheCall = (factory, options) => {
|
|
3
|
+
let cache;
|
|
4
|
+
const { onShouldCache = () => {
|
|
5
|
+
return true;
|
|
6
|
+
}, onCompare = (newArgs, oldArgs) => {
|
|
7
|
+
return isSameArray(newArgs, oldArgs);
|
|
8
|
+
}, } = options || {};
|
|
9
|
+
return ((...args) => {
|
|
10
|
+
const cacheable = onShouldCache();
|
|
11
|
+
if (cache && cacheable) {
|
|
12
|
+
const { parameters, returnValue } = cache;
|
|
13
|
+
if (onCompare(parameters, args)) {
|
|
14
|
+
return returnValue;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const returnValue = factory(...args);
|
|
18
|
+
if (cacheable) {
|
|
19
|
+
cache = {
|
|
20
|
+
parameters: args,
|
|
21
|
+
returnValue,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return returnValue;
|
|
25
|
+
});
|
|
26
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Reducer } from '@mic-rexjs/usecases';
|
|
2
|
+
import { RestArguments } from '@mic-rexjs/usecases/es/types';
|
|
3
|
+
export interface CacheableFactory {
|
|
4
|
+
(...args: RestArguments): unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface CacheCallOptions {
|
|
7
|
+
onShouldCache?(): boolean;
|
|
8
|
+
onCompare?(newArgs: RestArguments, oldArgs: RestArguments): boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface CallCache<T extends Reducer> {
|
|
11
|
+
parameters: Parameters<T>;
|
|
12
|
+
returnValue: ReturnType<T>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { cacheCall } from '../cacheCall';
|
|
2
|
+
export const cacheCalls = (sourceFactories, options) => {
|
|
3
|
+
const cachedFactories = {};
|
|
4
|
+
Object.entries(sourceFactories).forEach(([key, factory]) => {
|
|
5
|
+
cachedFactories[key] = cacheCall(factory, options);
|
|
6
|
+
});
|
|
7
|
+
return cachedFactories;
|
|
8
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { UseCaseHookParameters } from '../../hooks/useUseCase/types';
|
|
2
|
+
import { ReducerMap } from '@mic-rexjs/usecases';
|
|
3
|
+
import { UseCaseHookFullParameters } from './types';
|
|
4
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
5
|
+
export declare const fillArguments: <T, TReducers extends ReducerMap<import("@mic-rexjs/usecases").Reducer<unknown>>, TUseCaseOptions extends object>(args: UseCaseHookParameters, argumentTypes: UseCaseArgumentTypes) => UseCaseHookFullParameters<T, TReducers, TUseCaseOptions>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
2
|
+
import { UseCaseArgumentTypes } from '../../enums/UseCaseArgumentTypes';
|
|
3
|
+
export const fillArguments = (args, argumentTypes) => {
|
|
4
|
+
const [arg1, arg2, arg3, arg4, arg5] = args;
|
|
5
|
+
const hasEntity = (argumentTypes & UseCaseArgumentTypes.Entity) === UseCaseArgumentTypes.Entity;
|
|
6
|
+
const hasMode = (argumentTypes & UseCaseArgumentTypes.Mode) === UseCaseArgumentTypes.Mode;
|
|
7
|
+
if (hasEntity) {
|
|
8
|
+
if (hasMode) {
|
|
9
|
+
return [
|
|
10
|
+
arg1,
|
|
11
|
+
arg2,
|
|
12
|
+
arg3,
|
|
13
|
+
(arg4 || {}),
|
|
14
|
+
arg5 || [],
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
return [
|
|
18
|
+
arg1,
|
|
19
|
+
arg2,
|
|
20
|
+
UseCaseModes.Normal,
|
|
21
|
+
(arg3 || {}),
|
|
22
|
+
(arg4 || []),
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
if (hasMode) {
|
|
26
|
+
return [
|
|
27
|
+
null,
|
|
28
|
+
arg1,
|
|
29
|
+
arg2,
|
|
30
|
+
(arg3 || {}),
|
|
31
|
+
(arg4 || []),
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
null,
|
|
36
|
+
arg1,
|
|
37
|
+
UseCaseModes.Normal,
|
|
38
|
+
(arg2 || {}),
|
|
39
|
+
(arg3 || []),
|
|
40
|
+
];
|
|
41
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UseCaseModes } from '../../enums/UseCaseModes';
|
|
2
|
+
import { EntityGetter, UseCaseHookContextualOptions, UseCaseHookOptions } from '../../hooks/useUseCase/types';
|
|
3
|
+
import { EntityReducerMap, EntityUseCase, ReducerMap, UseCase } from '@mic-rexjs/usecases';
|
|
4
|
+
export type UseCaseHookFullParameters<T, TReducers extends ReducerMap, TUseCaseOptions extends object> = [
|
|
5
|
+
entity: T | EntityGetter<T>,
|
|
6
|
+
usecase: UseCase<TReducers, TUseCaseOptions> | EntityUseCase<T, TReducers & EntityReducerMap<T>, TUseCaseOptions>,
|
|
7
|
+
mode: UseCaseModes,
|
|
8
|
+
options: TUseCaseOptions | UseCaseHookOptions<T, TUseCaseOptions> | UseCaseHookContextualOptions<T>,
|
|
9
|
+
deps: unknown[]
|
|
10
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|