@mic-rexjs/usecases-react 1.3.32

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.
Files changed (46) hide show
  1. package/README.md +187 -0
  2. package/dist/index.min.js +2 -0
  3. package/dist/index.min.js.LICENSE.txt +9 -0
  4. package/es/components/UseCaseFragment/index.d.ts +3 -0
  5. package/es/components/UseCaseFragment/index.js +7 -0
  6. package/es/components/UseCaseFragment/types.d.ts +7 -0
  7. package/es/components/UseCaseFragment/types.js +1 -0
  8. package/es/configs/defaultUseCaseContext/index.d.ts +2 -0
  9. package/es/configs/defaultUseCaseContext/index.js +2 -0
  10. package/es/configs/usecaseContextMap/index.d.ts +3 -0
  11. package/es/configs/usecaseContextMap/index.js +1 -0
  12. package/es/configs/usecaseContextMap/types.d.ts +20 -0
  13. package/es/configs/usecaseContextMap/types.js +1 -0
  14. package/es/core/usecases/optionsGetterCellectionUseCase/index.d.ts +2 -0
  15. package/es/core/usecases/optionsGetterCellectionUseCase/index.js +13 -0
  16. package/es/core/usecases/optionsGetterCellectionUseCase/types.d.ts +8 -0
  17. package/es/core/usecases/optionsGetterCellectionUseCase/types.js +1 -0
  18. package/es/hooks/useOptionsTransfer/index.d.ts +3 -0
  19. package/es/hooks/useOptionsTransfer/index.js +15 -0
  20. package/es/hooks/useUseCase/index.d.ts +2 -0
  21. package/es/hooks/useUseCase/index.js +99 -0
  22. package/es/hooks/useUseCase/index.test.d.ts +1 -0
  23. package/es/hooks/useUseCase/index.test.js +670 -0
  24. package/es/hooks/useUseCase/methods/triggerCallbacks/index.d.ts +3 -0
  25. package/es/hooks/useUseCase/methods/triggerCallbacks/index.js +11 -0
  26. package/es/hooks/useUseCase/methods/triggerWatchers/index.d.ts +2 -0
  27. package/es/hooks/useUseCase/methods/triggerWatchers/index.js +10 -0
  28. package/es/hooks/useUseCase/types.d.ts +25 -0
  29. package/es/hooks/useUseCase/types.js +1 -0
  30. package/es/index.d.ts +2 -0
  31. package/es/index.js +2 -0
  32. package/lib/components/UseCaseFragment/index.js +20 -0
  33. package/lib/components/UseCaseFragment/types.js +5 -0
  34. package/lib/configs/defaultUseCaseContext/index.js +9 -0
  35. package/lib/configs/usecaseContextMap/index.js +8 -0
  36. package/lib/configs/usecaseContextMap/types.js +5 -0
  37. package/lib/core/usecases/optionsGetterCellectionUseCase/index.js +23 -0
  38. package/lib/core/usecases/optionsGetterCellectionUseCase/types.js +5 -0
  39. package/lib/hooks/useOptionsTransfer/index.js +23 -0
  40. package/lib/hooks/useUseCase/index.js +135 -0
  41. package/lib/hooks/useUseCase/index.test.js +951 -0
  42. package/lib/hooks/useUseCase/methods/triggerCallbacks/index.js +32 -0
  43. package/lib/hooks/useUseCase/methods/triggerWatchers/index.js +22 -0
  44. package/lib/hooks/useUseCase/types.js +5 -0
  45. package/lib/index.js +27 -0
  46. package/package.json +84 -0
package/README.md ADDED
@@ -0,0 +1,187 @@
1
+ ## Description
2
+ React-based solution for use usecases of Clean Architecture.
3
+
4
+ ## Install
5
+ ```bash
6
+ $ npm install --save @mic-rexjs/usecase-react
7
+ # -
8
+ $ yarn add --dev @mic-rexjs/usecase-react
9
+ ```
10
+
11
+ ## Links
12
+ - [Usage with Non-Entity Mode](#usage-with-non-entity-mode)
13
+ - [Useage with Entity Mode](#useage-with-entity-mode)
14
+ - [Test Demos](#test-demos)
15
+
16
+ ## Usage with Non-Entity Mode
17
+ ```tsx
18
+ // a.ts
19
+ import { Reducers } from '@mic-rexjs/usecases';
20
+
21
+ type MathReducers = Reducers<{
22
+ add(value1: number, value2: number): number;
23
+
24
+ subtraction(value1: number, value2: number): number;
25
+ }>;
26
+
27
+ const mathUseCase = (): MathReducers => {
28
+ const add = (value1: number, value2: number): number => {
29
+ return value1 + value2;
30
+ };
31
+
32
+ const subtraction = (value1: number, value2: number): number => {
33
+ return value1 - value2;
34
+ };
35
+
36
+ return { add, subtraction };
37
+ };
38
+
39
+ // b.tsx
40
+ const MyComponent = (): React.ReactElement => {
41
+ const { add, subtraction } = useUseCase(mathUseCase);
42
+
43
+ // you can use these reducers any where, and they will be never updated.
44
+ add(1, 2);
45
+ subtraction(5, 3);
46
+
47
+ // ...
48
+ };
49
+ ```
50
+
51
+ ## Useage with Entity Mode
52
+ ```tsx
53
+ // a.ts
54
+ import {
55
+ objectUseCase,
56
+ ObjectReducers,
57
+ EntityGenerator,
58
+ EntityReducers
59
+ } from '@mic-rexjs/usecases';
60
+
61
+ interface File {
62
+ path: string;
63
+ content: string;
64
+ }
65
+
66
+ interface FileUseCaseOptions {
67
+ maxContentLength?: number;
68
+ }
69
+
70
+ // All reducers should provide the first argument with an entity type T, such as `file: T`.
71
+ type FileReducers<T extends File> = EntityReducers<
72
+ T,
73
+ {
74
+ writeFile(entity: T, content: string): EntityGenerator<T, string>;
75
+ isTxt(entity: T): boolean;
76
+ },
77
+ // optional to extends an existed reducers
78
+ ObjectReducers<T>
79
+ >;
80
+
81
+ const fileUseCase = <T extends File>({ maxContentLength = 2000 }: FileUseCaseOptions = {}): FileReducers<T> => {
82
+ /**
83
+ * if you have not extends an existed reducers,
84
+ * you should call `entityUseCase` at here,
85
+ * such as `const entityReducers = entityUseCase<T>()`.
86
+ */
87
+ const objectReducers = objectUseCase<T>();
88
+
89
+ const writeFile = function* (entity: T, content: string): EntityGenerator<T, string> {
90
+ const { content: prevContent } = entity;
91
+ const newContent = prevContent + content;
92
+
93
+ if (newContent.length > maxContentLength) {
94
+ throw 'max length error';
95
+ }
96
+
97
+ // set new entity by yield expression
98
+ yield {
99
+ ...entity,
100
+ content: newContent,
101
+ };
102
+
103
+ // return the new content
104
+ return newContent;
105
+ };
106
+
107
+ const isTxt = (entity: T): boolean => {
108
+ const { path } = entity;
109
+
110
+ return path.endsWith('.txt');
111
+ };
112
+
113
+ return { ...objectReducers, writeFile, isTxt };
114
+ };
115
+
116
+ // b.tsx
117
+ import { useUseCase } from '@mic-rexjs/usecase-react';
118
+ import ReactDOM from 'react-dom';
119
+
120
+ const ParentComponent = ({ children }: React.PropsWithChildren): React.ReactElement => {
121
+ // Pass a default entity to initialize usecase, this usecase must be unique, just like `react context`.
122
+ const [entity, reducers, Provider] = useUseCase({ path: '', content: '' }, fileUseCase);
123
+ const { path } = entity;
124
+ const { writeFile } = reducers;
125
+
126
+ const onClick = (): void => {
127
+ // update entity
128
+ writeFile('hello world');
129
+ };
130
+
131
+ return (
132
+ // There's no need `value` property
133
+ <Provider>
134
+ <div>
135
+ <header>file path is: {path}</header>
136
+ <main>{children}</main>
137
+ <footer>
138
+ <button onClick={onClick}>write file</button>
139
+ </footer>
140
+ </div>
141
+ </Provider>
142
+ );
143
+ };
144
+
145
+ const ChildComponent = (): React.ReactElement => {
146
+ /**
147
+ * use a usecase which has initialzed in parent component,
148
+ * just like `useContext()`, but the parameter is a usecase.
149
+ */
150
+ const [entity, reducers] = useUseCase(fileUseCase);
151
+ const { content } = entity;
152
+ const { isTxt, writeFile } = reducers;
153
+
154
+ const onClick = (): void => {
155
+ // also, you can update entity at child component
156
+ writeFile('hello China');
157
+ };
158
+
159
+ /**
160
+ * reducers will be updated with entity change,
161
+ * so, you can add some reducers to deps.
162
+ */
163
+ const ext = useMemo((): string => {
164
+ return isTxt() ? '.txt' : '.js';
165
+ }, [isTxt]);
166
+
167
+ return (
168
+ <div>
169
+ <header>ext: {ext}</header>
170
+ <main>{content}</main>
171
+ <footer>
172
+ <button onClick={onClick}>write file</button>
173
+ </footer>
174
+ </div>
175
+ );
176
+ };
177
+
178
+ ReactDOM.render(
179
+ <ParentComponent>
180
+ <ChildComponent />
181
+ </ParentComponent>,
182
+ document.body
183
+ );
184
+ ```
185
+
186
+ ## Test Demos
187
+ - [useUseCase](https://github.com/mic-rexjs/usecase-react/blob/main/src/entityUseCase/index.test.ts)
@@ -0,0 +1,2 @@
1
+ /*! For license information please see index.min.js.LICENSE.txt */
2
+ !function(e,r){if("object"==typeof exports&&"object"==typeof module)module.exports=r(require("react"),require("ahooks"),require("@mic-rexjs/usecases"));else if("function"==typeof define&&define.amd)define(["react","ahooks","@mic-rexjs/usecases"],r);else{var t="object"==typeof exports?r(require("react"),require("ahooks"),require("@mic-rexjs/usecases")):r(e.react,e.ahooks,e["@mic-rexjs/usecases"]);for(var n in t)("object"==typeof exports?exports:e)[n]=t[n]}}(this,((e,r,t)=>(()=>{"use strict";var n={251:(e,r,t)=>{var n=t(156),o=Symbol.for("react.element"),u=(Symbol.for("react.fragment"),Object.prototype.hasOwnProperty),i=n.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,a={key:!0,ref:!0,__self:!0,__source:!0};r.jsx=function(e,r,t){var n,c={},f=null,l=null;for(n in void 0!==t&&(f=""+t),void 0!==r.key&&(f=""+r.key),void 0!==r.ref&&(l=r.ref),r)u.call(r,n)&&!a.hasOwnProperty(n)&&(c[n]=r[n]);if(e&&e.defaultProps)for(n in r=e.defaultProps)void 0===c[n]&&(c[n]=r[n]);return{$$typeof:o,type:e,key:f,ref:l,props:c,_owner:i.current}}},893:(e,r,t)=>{e.exports=t(251)},112:e=>{e.exports=t},749:e=>{e.exports=r},156:r=>{r.exports=e}},o={};function u(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={exports:{}};return n[e](t,t.exports,u),t.exports}u.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return u.d(r,{a:r}),r},u.d=(e,r)=>{for(var t in r)u.o(r,t)&&!u.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},u.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),u.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var i={};return(()=>{u.r(i),u.d(i,{UseCaseFragment:()=>g,useUseCase:()=>O});var e=u(893),r=u(156),t=u.n(r);function n(e,r){(null==r||r>e.length)&&(r=e.length);for(var t=0,n=new Array(r);t<r;t++)n[t]=e[t];return n}function o(e,r){if(e){if("string"==typeof e)return n(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);return"Object"===t&&e.constructor&&(t=e.constructor.name),"Map"===t||"Set"===t?Array.from(e):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?n(e,r):void 0}}function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function c(e,r,t){return(r=function(e){var r=function(e,r){if("object"!==a(e)||null===e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!==a(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"===a(r)?r:String(r)}(r))in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function f(e,r){return function(e){if(Array.isArray(e))return e}(e)||function(e,r){var t=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=t){var n,o,u,i,a=[],c=!0,f=!1;try{if(u=(t=t.call(e)).next,0===r){if(Object(t)!==t)return;c=!1}else for(;!(c=(n=u.call(t)).done)&&(a.push(n.value),a.length!==r);c=!0);}catch(e){f=!0,o=e}finally{try{if(!c&&null!=t.return&&(i=t.return(),Object(i)!==i))return}finally{if(f)throw o}}return a}}(e,r)||o(e,r)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}var l=u(749),s=(0,r.createContext)(null),y=new Map,p=function(e,r,t){for(var n=0,o=Object.entries(e);n<o.length;n++){var u=f(o[n],2),i=u[0],a=u[1];(null==r?void 0:r[i])!==(null==t?void 0:t[i])&&a(r,t)}};function b(e,r){(null==r||r>e.length)&&(r=e.length);for(var t=0,n=new Array(r);t<r;t++)n[t]=e[t];return n}var v=u(112),m=["stateless","watch","onChange","options"];function d(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function h(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?d(Object(t),!0).forEach((function(r){c(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):d(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}var O=function(e,u,i,a){var c,d=f((0,r.useState)("function"==typeof u),1)[0],O=f((0,r.useState)(d?e:null),2),g=O[0],j=O[1],S=(d?i:u)||{},w=S.stateless,x=(S.watch,S.onChange,S.options),P=function(e,r){if(null==e)return{};var t,n,o=function(e,r){if(null==e)return{};var t,n,o={},u=Object.keys(e);for(n=0;n<u.length;n++)t=u[n],r.indexOf(t)>=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(e);for(n=0;n<u.length;n++)t=u[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}(S,m),_=(0,r.useRef)([]),C=(d?a:i)||[],A=f((0,r.useState)((function(){return d?u:e})),1)[0],E=f((0,r.useState)((function(){var e=y,t=A;if(e.has(t))return e.get(t);if(!d)return s;var n=(0,r.createContext)(null);return e.set(t,n),n})),1)[0],M=f((0,r.useContext)(E)||[],3),I=M[0],k=M[1],T=M[2],R=(0,r.useMemo)((function(){return d?w?"function"!=typeof e?e:e():g:I}),[d,I,w,g,e]),U=(0,l.useMemoizedFn)((function(){var e=h(h({},P),x);return d?(0,(0,v.entityReducerUseCase)().createEntityReducers)(R,A,h(h({},e),{},{onChange:function(e,r){d&&!w&&j(e),function(e,r,t){var n,o=function(e,r){var t="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!t){if(Array.isArray(e)||(t=function(e,r){if(e){if("string"==typeof e)return b(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);return"Object"===t&&e.constructor&&(t=e.constructor.name),"Map"===t||"Set"===t?Array.from(e):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?b(e,r):void 0}}(e))||r&&e&&"number"==typeof e.length){t&&(e=t);var n=0,o=function(){};return{s:o,n:function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var u,i=!0,a=!1;return{s:function(){t=t.call(e)},n:function(){var e=t.next();return i=e.done,e},e:function(e){a=!0,u=e},f:function(){try{i||null==t.return||t.return()}finally{if(a)throw u}}}}(e);try{for(o.s();!(n=o.n()).done;){var u=(0,n.value)(),i=u.onChange,a=u.watch;null==i||i(r,t),a&&p(a,r,t)}}catch(e){o.e(e)}finally{o.f()}}(_.current,e,r)},onGenerate:function(e,r){return r}})):k||A(e)})),q=r.useMemo.call(null,U,[R,U].concat(function(e){if(Array.isArray(e))return n(e)}(c=C)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(c)||o(c)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}())),D=(0,r.useMemo)((function(){return!d&&T?T:(e=_.current,{addOptionsGetter:function(r){e.unshift(r)},removeOptionsGetter:function(r){var t=e.indexOf(r);-1!==t&&e.splice(t,1)}});var e}),[d,T]),F=(0,r.useMemo)((function(){return[R,q,D]}),[R,q,D]),G=(0,l.useLatest)(F),L=f((0,r.useState)((function(){return function(e){var r=e.children,n=E.Provider;return t().createElement(n,{value:G.current},r)}})),1)[0],$=(0,r.useMemo)((function(){return d?[R,q,L]:[R,q]}),[R,q,d,L]),N=(0,r.useMemo)((function(){return E===s?q:$}),[E,q,$]);return function(e,r){var t=r.addOptionsGetter,n=r.removeOptionsGetter,o=(0,l.usePrevious)(n),u=(0,l.useMemoizedFn)((function(){return e}));(0,l.useCreation)((function(){null==o||o(u),t(u)}),[t,o,u]),(0,l.useUnmount)((function(){n(u)}))}(S,D),N},g=function(t){var n=t.usecase,o=t.watch,u=t.onChange;return O(n,{watch:o,onChange:u}),(0,e.jsx)(r.Fragment,{})}})(),i})()));
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license React
3
+ * react-jsx-runtime.production.min.js
4
+ *
5
+ * Copyright (c) Facebook, Inc. and its affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
@@ -0,0 +1,3 @@
1
+ import { UseCaseFragmentProps } from './types';
2
+ import { EntityReducers } from '@mic-rexjs/usecases';
3
+ export declare const UseCaseFragment: <T, TReducers extends EntityReducers<T>>({ usecase, watch, onChange, }: UseCaseFragmentProps<T, TReducers>) => React.ReactElement;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
3
+ import { useUseCase } from '../../hooks/useUseCase';
4
+ export const UseCaseFragment = ({ usecase, watch, onChange, }) => {
5
+ void useUseCase(usecase, { watch, onChange });
6
+ return _jsx(Fragment, {});
7
+ };
@@ -0,0 +1,7 @@
1
+ import { EntityReducers, EntityUseCase } from '@mic-rexjs/usecases';
2
+ import { EntityWatchMap } from '../../hooks/useUseCase/types';
3
+ export interface UseCaseFragmentProps<T, TReducers extends EntityReducers<T>> {
4
+ usecase: EntityUseCase<T, TReducers & EntityReducers<T>>;
5
+ watch?: EntityWatchMap<T>;
6
+ onChange?(prevEntity: T, nextEntity: T): void;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare const defaultUseCaseContext: import("react").Context<null>;
@@ -0,0 +1,2 @@
1
+ import { createContext } from 'react';
2
+ export const defaultUseCaseContext = createContext(null);
@@ -0,0 +1,3 @@
1
+ import { EntityReducers } from '@mic-rexjs/usecases';
2
+ import { UseCaseContextMap } from './types';
3
+ export declare const usecaseContextMap: UseCaseContextMap<unknown, EntityReducers<unknown>>;
@@ -0,0 +1 @@
1
+ export const usecaseContextMap = new Map();
@@ -0,0 +1,20 @@
1
+ /// <reference types="react" />
2
+ import { OptionsGetterCollectionReducers } from '../../core/usecases/optionsGetterCellectionUseCase/types';
3
+ import { AsyncEntityGenerator, EntityGenerator, EntityReducers, EntityUseCase } from '@mic-rexjs/usecases';
4
+ export type ContextualEntityReducer<T> = T extends (entity: infer TEntity, ...args: infer TArgs) => infer TReturn ? (...args: TArgs) => TReturn extends AsyncEntityGenerator<TEntity, infer TResult> ? Promise<TResult> : TReturn extends EntityGenerator<TEntity, infer TResult> ? TResult : TReturn : never;
5
+ export type ContextualEntityReducers<T> = {
6
+ [K in keyof T]: ContextualEntityReducer<T[K]>;
7
+ };
8
+ export type UseCaseContext<T, TReducers> = [entity: T, reducers: ContextualEntityReducers<TReducers>];
9
+ export type UseCaseContextWithCollectionReducers<T, TReducers, TOptions> = [
10
+ ...context: UseCaseContext<T, TReducers>,
11
+ collectionReducers: OptionsGetterCollectionReducers<TOptions>
12
+ ];
13
+ export interface UseCaseProvider extends React.FC<React.PropsWithChildren> {
14
+ }
15
+ export type UseCaseContextWithProvider<T, TReducers> = [
16
+ ...args: UseCaseContext<T, TReducers>,
17
+ Provider: UseCaseProvider
18
+ ];
19
+ export interface UseCaseContextMap<T, TReducers extends EntityReducers<T>, TOptions = object> extends Map<EntityUseCase<T, TReducers>, React.Context<UseCaseContextWithCollectionReducers<T, TReducers, TOptions> | null>> {
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { OptionsGetter, OptionsGetterCollectionReducers } from './types';
2
+ export declare const optionsGetterCollectionUseCase: <T>(collection: OptionsGetter<T>[]) => OptionsGetterCollectionReducers<T>;
@@ -0,0 +1,13 @@
1
+ export const optionsGetterCollectionUseCase = (collection) => {
2
+ const addOptionsGetter = (getter) => {
3
+ collection.unshift(getter);
4
+ };
5
+ const removeOptionsGetter = (getter) => {
6
+ const index = collection.indexOf(getter);
7
+ if (index === -1) {
8
+ return;
9
+ }
10
+ collection.splice(index, 1);
11
+ };
12
+ return { addOptionsGetter, removeOptionsGetter };
13
+ };
@@ -0,0 +1,8 @@
1
+ import { Reducers } from '@mic-rexjs/usecases';
2
+ export interface OptionsGetter<T> {
3
+ (): T;
4
+ }
5
+ export type OptionsGetterCollectionReducers<T> = Reducers<{
6
+ addOptionsGetter(getter: OptionsGetter<T>): void;
7
+ removeOptionsGetter(getter: OptionsGetter<T>): void;
8
+ }>;
@@ -0,0 +1,3 @@
1
+ import { UseCaseHookOptions } from '../useUseCase/types';
2
+ import { OptionsGetterCollectionReducers } from '../../core/usecases/optionsGetterCellectionUseCase/types';
3
+ export declare const useOptionsTransfer: <T, TOptions extends object>(options: UseCaseHookOptions<T, TOptions>, optionsGetterListReducers: OptionsGetterCollectionReducers<UseCaseHookOptions<T, TOptions>>) => void;
@@ -0,0 +1,15 @@
1
+ import { useCreation, useMemoizedFn, usePrevious, useUnmount } from 'ahooks';
2
+ export const useOptionsTransfer = (options, optionsGetterListReducers) => {
3
+ const { addOptionsGetter, removeOptionsGetter } = optionsGetterListReducers;
4
+ const prevRemoveOptionsGetter = usePrevious(removeOptionsGetter);
5
+ const getOptions = useMemoizedFn(() => {
6
+ return options;
7
+ });
8
+ useCreation(() => {
9
+ prevRemoveOptionsGetter?.(getOptions);
10
+ addOptionsGetter(getOptions);
11
+ }, [addOptionsGetter, prevRemoveOptionsGetter, getOptions]);
12
+ useUnmount(() => {
13
+ removeOptionsGetter(getOptions);
14
+ });
15
+ };
@@ -0,0 +1,2 @@
1
+ import { UseCaseHook } from './types';
2
+ export declare const useUseCase: UseCaseHook;
@@ -0,0 +1,99 @@
1
+ import { useLatest, useMemoizedFn } from 'ahooks';
2
+ import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
3
+ import { defaultUseCaseContext } from '../../configs/defaultUseCaseContext';
4
+ import { usecaseContextMap } from '../../configs/usecaseContextMap';
5
+ import { optionsGetterCollectionUseCase } from '../../core/usecases/optionsGetterCellectionUseCase';
6
+ import { triggerCallbacks } from './methods/triggerCallbacks';
7
+ import { useOptionsTransfer } from '../useOptionsTransfer';
8
+ import { entityReducerUseCase } from '@mic-rexjs/usecases';
9
+ export const useUseCase = ((arg1, arg2, arg3, arg4) => {
10
+ const [hasDefaultEntity] = useState(typeof arg2 === 'function');
11
+ const [entityState, setEntityState] = useState(hasDefaultEntity ? arg1 : null);
12
+ const options = (hasDefaultEntity ? arg3 : arg2) || {};
13
+ const { stateless, watch, onChange, options: usecaseOptions, ...restUseCaseOptions } = options;
14
+ const optionsGetterListRef = useRef([]);
15
+ const deps = (hasDefaultEntity ? arg4 : arg3) || [];
16
+ const [usecase] = useState(() => {
17
+ return hasDefaultEntity
18
+ ? arg2
19
+ : arg1;
20
+ });
21
+ const [context] = useState(() => {
22
+ const map = usecaseContextMap;
23
+ const entityUseCase = usecase;
24
+ if (map.has(entityUseCase)) {
25
+ return map.get(entityUseCase);
26
+ }
27
+ if (!hasDefaultEntity) {
28
+ return defaultUseCaseContext;
29
+ }
30
+ const ctx = createContext(null);
31
+ map.set(entityUseCase, ctx);
32
+ return ctx;
33
+ });
34
+ const [contextEntity, contextEntityReducers, contextCollectionReducers] = useContext(context) || [];
35
+ const entity = useMemo(() => {
36
+ if (!hasDefaultEntity) {
37
+ return contextEntity;
38
+ }
39
+ if (!stateless) {
40
+ return entityState;
41
+ }
42
+ if (typeof arg1 !== 'function') {
43
+ return arg1;
44
+ }
45
+ return arg1();
46
+ }, [hasDefaultEntity, contextEntity, stateless, entityState, arg1]);
47
+ const initReducers = useMemoizedFn(() => {
48
+ const mergedOptions = { ...restUseCaseOptions, ...usecaseOptions };
49
+ if (!hasDefaultEntity) {
50
+ return contextEntityReducers || usecase(mergedOptions);
51
+ }
52
+ const { createEntityReducers } = entityReducerUseCase();
53
+ return createEntityReducers(entity, usecase, {
54
+ ...mergedOptions,
55
+ onChange(newEntity, prevEntity) {
56
+ if (hasDefaultEntity && !stateless) {
57
+ setEntityState(newEntity);
58
+ }
59
+ triggerCallbacks(optionsGetterListRef.current, newEntity, prevEntity);
60
+ },
61
+ onGenerate(newEntity, result) {
62
+ return result;
63
+ },
64
+ });
65
+ });
66
+ const reducers = useMemo.call(null, initReducers, [entity, initReducers, ...deps]);
67
+ const collectionReducers = useMemo(() => {
68
+ if (!hasDefaultEntity && contextCollectionReducers) {
69
+ return contextCollectionReducers;
70
+ }
71
+ return optionsGetterCollectionUseCase(optionsGetterListRef.current);
72
+ }, [hasDefaultEntity, contextCollectionReducers]);
73
+ const contextValueWithCollectionReducers = useMemo(() => {
74
+ return [entity, reducers, collectionReducers];
75
+ }, [entity, reducers, collectionReducers]);
76
+ const contextValueWithCollectionReducersRef = useLatest(contextValueWithCollectionReducers);
77
+ const [Provider] = useState(() => {
78
+ return ({ children }) => {
79
+ const { Provider: ContextProvider } = context;
80
+ return React.createElement(ContextProvider, {
81
+ value: contextValueWithCollectionReducersRef.current,
82
+ }, children);
83
+ };
84
+ });
85
+ const contextValue = useMemo(() => {
86
+ if (hasDefaultEntity) {
87
+ return [entity, reducers, Provider];
88
+ }
89
+ return [entity, reducers];
90
+ }, [entity, reducers, hasDefaultEntity, Provider]);
91
+ const result = useMemo(() => {
92
+ if (context === defaultUseCaseContext) {
93
+ return reducers;
94
+ }
95
+ return contextValue;
96
+ }, [context, reducers, contextValue]);
97
+ void useOptionsTransfer(options, collectionReducers);
98
+ return result;
99
+ });
@@ -0,0 +1 @@
1
+ export {};