@servicetitan/react-ioc 23.5.1 → 23.6.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/provider.d.ts.map +1 -1
- package/dist/provider.js +43 -36
- package/dist/provider.js.map +1 -1
- package/package.json +5 -7
- package/src/__tests__/await.test.tsx +14 -10
- package/src/__tests__/provide.test.tsx +1 -1
- package/src/__tests__/provider.test.tsx +20 -41
- package/src/__tests__/react-ioc.test.tsx +15 -15
- package/src/provider.tsx +57 -47
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACH,EAAE,EACF,iBAAiB,EACjB,YAAY,
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACH,EAAE,EACF,iBAAiB,EACjB,YAAY,EAKf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAa,UAAU,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAoB,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAIhE,oBAAY,6BAA6B,CAAC,CAAC,IACrC,wBAAwB,CAAC,CAAC,CAAC,GAC3B,wBAAwB,CAAC,CAAC,CAAC,CAAC;AAClC,oBAAY,4BAA4B,CAAC,CAAC,IAAI,iCAAiC,CAAC,CAAC,CAAC,CAAC;AACnF,oBAAY,mBAAmB,CAAC,CAAC,IAC3B,6BAA6B,CAAC,CAAC,CAAC,GAChC,4BAA4B,CAAC,CAAC,CAAC,CAAC;AAEtC,aAAK,wBAAwB,CAAC,CAAC,IACzB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACrB,gCAAgC,CAAC,CAAC,CAAC,GACnC,6BAA6B,CAAC,CAAC,CAAC,CAAC;AAEvC,aAAK,iCAAiC,CAAC,CAAC,IAClC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACrB,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAE3D,UAAU,gCAAgC,CAAC,CAAC;IACxC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,UAAU,6BAA6B,CAAC,CAAC;IACrC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,UAAU,wBAAwB,CAAC,CAAC;IAChC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjD,QAAQ,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,EAAE,IAAI,CAAC;CAClB;AA2JD,oBAAY,aAAa,GAAG,iBAAiB,CAAC;IAC1C,UAAU,CAAC,EAAE,6BAA6B,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,SAAS,CAAC,EAAE,4BAA4B,CAAC,GAAG,CAAC,EAAE,CAAC;IAChD,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,aAAa,CAAC,EAAE,YAAY,CAAC;CAChC,CAAC,CAAC;AAEH,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA6DtC,CAAC"}
|
package/dist/provider.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useContext, useEffect,
|
|
2
|
+
import { useState, useContext, useEffect, useRef, } from 'react';
|
|
3
3
|
import { Container } from 'inversify';
|
|
4
4
|
import { Await } from './await';
|
|
5
5
|
import { ContainerContext } from './common';
|
|
@@ -33,7 +33,7 @@ function getProvideTokenWithClass(entry) {
|
|
|
33
33
|
}
|
|
34
34
|
return [entry, entry];
|
|
35
35
|
}
|
|
36
|
-
function getStoreInstances(container, singletons = [], instances = []) {
|
|
36
|
+
function getStoreInstances(container, { singletons = [], instances = [] }) {
|
|
37
37
|
return [...singletons, ...instances].reduce((out, entry) => {
|
|
38
38
|
const [provide, useClass] = getProvideTokenWithClass(entry);
|
|
39
39
|
if (provide && useClass && container.isCurrentBound(provide) && isStore(useClass)) {
|
|
@@ -62,6 +62,9 @@ const bindEntry = (container, checkInherit) => (entry) => {
|
|
|
62
62
|
return container.bind(entry).to(entry);
|
|
63
63
|
};
|
|
64
64
|
const unbindEntry = (container) => (entry) => {
|
|
65
|
+
if (isProviderConfigEntryInheritable(entry) && !container.isBound(entry.provide)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
65
68
|
if (isClassProviderConfigEntryUseClass(entry) ||
|
|
66
69
|
isValueProviderConfigEntry(entry) ||
|
|
67
70
|
isClassProviderConfigEntryToken(entry)) {
|
|
@@ -69,54 +72,58 @@ const unbindEntry = (container) => (entry) => {
|
|
|
69
72
|
}
|
|
70
73
|
return container.unbind(entry);
|
|
71
74
|
};
|
|
75
|
+
function bindEntries(container, { singletons = [], instances = [] }) {
|
|
76
|
+
singletons.map(bindEntry(container, true)).forEach(binding => {
|
|
77
|
+
binding === null || binding === void 0 ? void 0 : binding.inSingletonScope();
|
|
78
|
+
});
|
|
79
|
+
instances.forEach(bindEntry(container, false));
|
|
80
|
+
}
|
|
81
|
+
function unbindEntries(container, { singletons = [], instances = [] }) {
|
|
82
|
+
[...singletons, ...instances].forEach(unbindEntry(container));
|
|
83
|
+
}
|
|
84
|
+
function initializeStores(stores, onError) {
|
|
85
|
+
var _a;
|
|
86
|
+
const promises = [];
|
|
87
|
+
for (const instance of stores) {
|
|
88
|
+
let promise;
|
|
89
|
+
try {
|
|
90
|
+
promise = (_a = instance.initialize) === null || _a === void 0 ? void 0 : _a.call(instance);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
onError(e);
|
|
94
|
+
}
|
|
95
|
+
if (promise && typeof promise.catch === 'function') {
|
|
96
|
+
promises.push(promise.catch(onError));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return promises;
|
|
100
|
+
}
|
|
101
|
+
function disposeStores(stores) {
|
|
102
|
+
var _a;
|
|
103
|
+
for (const instance of stores) {
|
|
104
|
+
(_a = instance.dispose) === null || _a === void 0 ? void 0 : _a.call(instance);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
72
107
|
export const Provider = ({ singletons, instances, loadingFallback = defaultLoadingFallback, errorFallback = defaultErrorFallback, children, }) => {
|
|
73
108
|
const parentContainer = useContext(ContainerContext);
|
|
74
109
|
const containerRef = useRef();
|
|
75
110
|
const [promises, setPromises] = useState([]);
|
|
76
111
|
const [error, setError] = useState(false);
|
|
77
|
-
|
|
112
|
+
useEffect(() => {
|
|
78
113
|
const container = new Container();
|
|
79
114
|
container.parent = parentContainer;
|
|
80
|
-
singletons === null || singletons === void 0 ? void 0 : singletons.map(bindEntry(container, true)).forEach(binding => {
|
|
81
|
-
binding === null || binding === void 0 ? void 0 : binding.inSingletonScope();
|
|
82
|
-
});
|
|
83
|
-
instances === null || instances === void 0 ? void 0 : instances.forEach(bindEntry(container, false));
|
|
84
|
-
const storeInstances = getStoreInstances(container, singletons, instances);
|
|
85
|
-
const promises = [];
|
|
86
|
-
for (const instance of storeInstances) {
|
|
87
|
-
if (instance.initialize) {
|
|
88
|
-
let promise;
|
|
89
|
-
try {
|
|
90
|
-
promise = instance.initialize();
|
|
91
|
-
}
|
|
92
|
-
catch (_a) {
|
|
93
|
-
setError(true);
|
|
94
|
-
}
|
|
95
|
-
if (promise && typeof promise.catch === 'function') {
|
|
96
|
-
promises.push(promise.catch(() => {
|
|
97
|
-
setError(true);
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
115
|
containerRef.current = container;
|
|
116
|
+
bindEntries(container, { singletons, instances });
|
|
117
|
+
const promises = initializeStores(getStoreInstances(container, { singletons, instances }), () => setError(true));
|
|
103
118
|
setPromises(promises);
|
|
104
|
-
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
105
|
-
useEffect(() => {
|
|
106
119
|
return () => {
|
|
107
120
|
const container = containerRef.current;
|
|
108
121
|
if (!container) {
|
|
109
122
|
return;
|
|
110
123
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
instances === null || instances === void 0 ? void 0 : instances.forEach(unbind);
|
|
115
|
-
for (const instance of storeInstances) {
|
|
116
|
-
if (instance.dispose) {
|
|
117
|
-
instance.dispose();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
124
|
+
unbindEntries(container, { singletons, instances });
|
|
125
|
+
disposeStores(getStoreInstances(container, { singletons, instances }));
|
|
126
|
+
setPromises([]);
|
|
120
127
|
};
|
|
121
128
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
122
129
|
if (!containerRef.current) {
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAIH,QAAQ,EACR,UAAU,EACV,SAAS,EACT,
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/react-ioc",
|
|
3
|
-
"version": "23.
|
|
3
|
+
"version": "23.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/react-ioc",
|
|
6
6
|
"repository": {
|
|
@@ -20,12 +20,10 @@
|
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@servicetitan/startup-jest": "^1.1.0",
|
|
23
|
-
"@testing-library/jest-dom": "^6.4.
|
|
24
|
-
"@testing-library/react": "^15.0.
|
|
23
|
+
"@testing-library/jest-dom": "^6.4.5",
|
|
24
|
+
"@testing-library/react": "^15.0.7",
|
|
25
25
|
"@types/react": "~18.3.0",
|
|
26
|
-
"
|
|
27
|
-
"react": "~18.3.1",
|
|
28
|
-
"react-test-renderer": "~18.3.1"
|
|
26
|
+
"react": "~18.3.1"
|
|
29
27
|
},
|
|
30
28
|
"peerDependencies": {
|
|
31
29
|
"react": ">=17.0.2"
|
|
@@ -36,5 +34,5 @@
|
|
|
36
34
|
"cli": {
|
|
37
35
|
"webpack": false
|
|
38
36
|
},
|
|
39
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "d7e765992dd65d46e2dca48c150bd611af6a034f"
|
|
40
38
|
}
|
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { render, waitFor } from '@testing-library/react';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
|
|
2
4
|
import { Await } from '../await';
|
|
3
|
-
import { waitFor } from '@testing-library/react';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
describe('[react-ioc] Await', () => {
|
|
7
|
+
const testContent = 'hello';
|
|
8
|
+
|
|
9
|
+
const TestContent = () => <div role="content">{testContent}</div>;
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const { root } = TestRenderer.create(
|
|
11
|
+
const subject = () =>
|
|
12
|
+
render(
|
|
10
13
|
<Await promises={[]}>
|
|
11
14
|
<TestContent />
|
|
12
15
|
</Await>
|
|
13
16
|
);
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
test('renders content', async () => {
|
|
19
|
+
const { container } = subject();
|
|
20
|
+
|
|
21
|
+
await waitFor(() => {
|
|
22
|
+
expect(container).toHaveTextContent(testContent);
|
|
19
23
|
});
|
|
20
24
|
});
|
|
21
25
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
2
3
|
import { FC, Fragment, PropsWithChildren } from 'react';
|
|
3
4
|
|
|
4
5
|
import { provide } from '../provide';
|
|
5
|
-
import { render, screen } from '@testing-library/react';
|
|
6
6
|
|
|
7
7
|
jest.mock('../provider', () => ({
|
|
8
8
|
Provider: ({ children, ...props }: PropsWithChildren<any>) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { act, render, waitFor } from '@testing-library/react';
|
|
1
2
|
import { PropsWithChildren, ReactElement, ReactNode, useEffect } from 'react';
|
|
2
3
|
import {
|
|
3
4
|
inject,
|
|
@@ -8,8 +9,6 @@ import {
|
|
|
8
9
|
Provider,
|
|
9
10
|
ProviderProps,
|
|
10
11
|
} from '..';
|
|
11
|
-
import TestRenderer from 'react-test-renderer';
|
|
12
|
-
import { waitFor } from '@testing-library/react';
|
|
13
12
|
|
|
14
13
|
@injectable()
|
|
15
14
|
class StatStore {
|
|
@@ -88,15 +87,13 @@ describe('[react-ioc] Provider', () => {
|
|
|
88
87
|
beforeEach(() => (stat = new StatStore()));
|
|
89
88
|
|
|
90
89
|
const subject = (children: ReactNode) =>
|
|
91
|
-
|
|
90
|
+
render(
|
|
92
91
|
<Provider singletons={[{ provide: StatStore, useValue: stat }]}>{children}</Provider>
|
|
93
92
|
);
|
|
94
93
|
|
|
95
94
|
const expectQueueRenderToBe = (queueRender: string[]) =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
expect(stat.queueRender).toEqual(queueRender);
|
|
99
|
-
});
|
|
95
|
+
waitFor(() => {
|
|
96
|
+
expect(stat.queueRender).toEqual(queueRender);
|
|
100
97
|
});
|
|
101
98
|
|
|
102
99
|
describe('with singletons', () => {
|
|
@@ -245,13 +242,7 @@ describe('[react-ioc] Provider', () => {
|
|
|
245
242
|
<TestProvider store={StoreWithInitialize} singletons={[StoreWithInitialize]} />
|
|
246
243
|
);
|
|
247
244
|
|
|
248
|
-
expect(stat.
|
|
249
|
-
|
|
250
|
-
await TestRenderer.act(async () => {
|
|
251
|
-
await waitFor(() => {
|
|
252
|
-
expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
|
|
253
|
-
});
|
|
254
|
-
});
|
|
245
|
+
expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
|
|
255
246
|
|
|
256
247
|
await expectQueueRenderToBe(['StoreWithInitialize-1']);
|
|
257
248
|
});
|
|
@@ -263,14 +254,12 @@ describe('[react-ioc] Provider', () => {
|
|
|
263
254
|
</TestProvider>
|
|
264
255
|
);
|
|
265
256
|
|
|
266
|
-
await
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
});
|
|
257
|
+
await waitFor(() => {
|
|
258
|
+
expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
|
|
259
|
+
});
|
|
270
260
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
});
|
|
261
|
+
await waitFor(() => {
|
|
262
|
+
expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-2');
|
|
274
263
|
});
|
|
275
264
|
|
|
276
265
|
expect(stat.queueCreate).toEqual(['StoreWithInitialize-1', 'StoreWithInitialize-2']);
|
|
@@ -288,10 +277,8 @@ describe('[react-ioc] Provider', () => {
|
|
|
288
277
|
</TestProvider>
|
|
289
278
|
);
|
|
290
279
|
|
|
291
|
-
await
|
|
292
|
-
|
|
293
|
-
expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
|
|
294
|
-
});
|
|
280
|
+
await waitFor(() => {
|
|
281
|
+
expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
|
|
295
282
|
});
|
|
296
283
|
|
|
297
284
|
expect(stat.queueCreate).toEqual(['StoreWithInitialize-1']);
|
|
@@ -314,38 +301,30 @@ describe('[react-ioc] Provider', () => {
|
|
|
314
301
|
}
|
|
315
302
|
}
|
|
316
303
|
|
|
317
|
-
const subject = async (
|
|
318
|
-
children
|
|
319
|
-
): Promise<ReturnType<typeof TestRenderer.create>> => {
|
|
320
|
-
let result: ReturnType<typeof TestRenderer.create> | undefined = undefined;
|
|
304
|
+
const subject = async (children: ReactElement) => {
|
|
305
|
+
const result = render(children);
|
|
321
306
|
|
|
322
|
-
await
|
|
323
|
-
|
|
324
|
-
await new Promise<void>(resolve => resolve());
|
|
325
|
-
result = TestRenderer.create(children);
|
|
307
|
+
await act(async () => {
|
|
308
|
+
await new Promise(process.nextTick);
|
|
326
309
|
});
|
|
327
310
|
|
|
328
|
-
if (!result) {
|
|
329
|
-
throw new Error();
|
|
330
|
-
}
|
|
331
|
-
|
|
332
311
|
return result;
|
|
333
312
|
};
|
|
334
313
|
|
|
335
314
|
test('async error initialization shows error', async () => {
|
|
336
|
-
const {
|
|
315
|
+
const { container } = await subject(
|
|
337
316
|
<Provider singletons={[StoreWithAsyncErrorInitialize]}>hello</Provider>
|
|
338
317
|
);
|
|
339
318
|
|
|
340
|
-
expect(
|
|
319
|
+
expect(container.querySelector('h2')).toBeTruthy();
|
|
341
320
|
});
|
|
342
321
|
|
|
343
322
|
test('sync error initialization shows error', async () => {
|
|
344
|
-
const {
|
|
323
|
+
const { container } = await subject(
|
|
345
324
|
<Provider singletons={[StoreWithErrorInitialize]}>hello</Provider>
|
|
346
325
|
);
|
|
347
326
|
|
|
348
|
-
expect(
|
|
327
|
+
expect(container.querySelector('h2')).toBeTruthy();
|
|
349
328
|
});
|
|
350
329
|
});
|
|
351
330
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
1
2
|
import { Component, createContext, useRef, FC, PropsWithChildren } from 'react';
|
|
2
3
|
import {
|
|
3
4
|
provide,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
symbolToken,
|
|
10
11
|
} from '..';
|
|
11
12
|
import { ContainerContext } from '../common';
|
|
12
|
-
import TestRenderer from 'react-test-renderer';
|
|
13
13
|
|
|
14
14
|
@injectable()
|
|
15
15
|
class SampleStore {
|
|
@@ -51,7 +51,7 @@ describe('[react-ioc]', () => {
|
|
|
51
51
|
const setContainer = (container: Container) => {
|
|
52
52
|
contextContainer = container;
|
|
53
53
|
};
|
|
54
|
-
|
|
54
|
+
render(
|
|
55
55
|
<Provider
|
|
56
56
|
singletons={[SampleStore, { provide: ANOTHER_STORE_TOKEN, useClass: AnotherStore }]}
|
|
57
57
|
>
|
|
@@ -79,7 +79,7 @@ describe('[react-ioc]', () => {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
render(<SampleProvider />);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
test('Unmounted component should unbind the depended store', () => {
|
|
@@ -89,7 +89,7 @@ describe('[react-ioc]', () => {
|
|
|
89
89
|
contextContainer = container;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
const renderer =
|
|
92
|
+
const renderer = render(
|
|
93
93
|
<Provider
|
|
94
94
|
singletons={[
|
|
95
95
|
SampleStore,
|
|
@@ -101,7 +101,7 @@ describe('[react-ioc]', () => {
|
|
|
101
101
|
</Provider>
|
|
102
102
|
);
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
renderer.unmount();
|
|
105
105
|
|
|
106
106
|
expect(() => contextContainer.get(SampleStore)).toThrow();
|
|
107
107
|
expect(() => contextContainer.get(ANOTHER_STORE_TOKEN)).toThrow();
|
|
@@ -115,7 +115,7 @@ describe('[react-ioc]', () => {
|
|
|
115
115
|
contextContainer = container;
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
render(
|
|
119
119
|
<Provider instances={[SampleStore]}>
|
|
120
120
|
<SampleConsumer setContainer={setContainer} />
|
|
121
121
|
</Provider>
|
|
@@ -140,7 +140,7 @@ describe('[react-ioc]', () => {
|
|
|
140
140
|
childContainer = container;
|
|
141
141
|
};
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
render(
|
|
144
144
|
<Provider singletons={[SampleStore]}>
|
|
145
145
|
<SampleConsumer setContainer={setParentContainer}>
|
|
146
146
|
<Provider singletons={[SampleStore]}>
|
|
@@ -168,7 +168,7 @@ describe('[react-ioc]', () => {
|
|
|
168
168
|
childContainer = container;
|
|
169
169
|
};
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
render(
|
|
172
172
|
<Provider singletons={[SampleStore]}>
|
|
173
173
|
<SampleConsumer setContainer={setParentContainer}>
|
|
174
174
|
<Provider>
|
|
@@ -196,7 +196,7 @@ describe('[react-ioc]', () => {
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
render(
|
|
200
200
|
<Provider singletons={[SampleStore]}>
|
|
201
201
|
<SampleComponent />
|
|
202
202
|
</Provider>
|
|
@@ -216,7 +216,7 @@ describe('[react-ioc]', () => {
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
render(
|
|
220
220
|
<Provider singletons={[SampleStore]}>
|
|
221
221
|
<SampleComponent />
|
|
222
222
|
</Provider>
|
|
@@ -243,7 +243,7 @@ describe('[react-ioc]', () => {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
render(
|
|
247
247
|
<Provider singletons={[SampleStore]}>
|
|
248
248
|
<SampleComponent />
|
|
249
249
|
</Provider>
|
|
@@ -282,8 +282,8 @@ describe('[react-ioc]', () => {
|
|
|
282
282
|
<SampleComponent />
|
|
283
283
|
</Provider>
|
|
284
284
|
);
|
|
285
|
-
const renderer =
|
|
286
|
-
renderer.
|
|
285
|
+
const renderer = render(<Component />);
|
|
286
|
+
renderer.rerender(<Component />);
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
test('store in transient scope usage with hooks must be initialized properly', () => {
|
|
@@ -300,7 +300,7 @@ describe('[react-ioc]', () => {
|
|
|
300
300
|
<SampleComponent />
|
|
301
301
|
</Provider>
|
|
302
302
|
);
|
|
303
|
-
const renderer =
|
|
304
|
-
renderer.
|
|
303
|
+
const renderer = render(<Component />);
|
|
304
|
+
renderer.rerender(<Component />);
|
|
305
305
|
});
|
|
306
306
|
});
|
package/src/provider.tsx
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
useState,
|
|
6
6
|
useContext,
|
|
7
7
|
useEffect,
|
|
8
|
-
useLayoutEffect,
|
|
9
8
|
useRef,
|
|
10
9
|
} from 'react';
|
|
11
10
|
|
|
@@ -105,8 +104,7 @@ function getProvideTokenWithClass<T>(
|
|
|
105
104
|
|
|
106
105
|
function getStoreInstances(
|
|
107
106
|
container: Container,
|
|
108
|
-
singletons
|
|
109
|
-
instances: ProviderConfigEntryInstances<any>[] = []
|
|
107
|
+
{ singletons = [], instances = [] }: Pick<ProviderProps, 'singletons' | 'instances'>
|
|
110
108
|
): Store[] {
|
|
111
109
|
return [...singletons, ...instances].reduce((out, entry) => {
|
|
112
110
|
const [provide, useClass] = getProvideTokenWithClass(entry);
|
|
@@ -147,6 +145,9 @@ const bindEntry =
|
|
|
147
145
|
};
|
|
148
146
|
|
|
149
147
|
const unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>) => {
|
|
148
|
+
if (isProviderConfigEntryInheritable(entry) && !container.isBound(entry.provide)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
150
151
|
if (
|
|
151
152
|
isClassProviderConfigEntryUseClass(entry) ||
|
|
152
153
|
isValueProviderConfigEntry(entry) ||
|
|
@@ -158,6 +159,49 @@ const unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>)
|
|
|
158
159
|
return container.unbind(entry);
|
|
159
160
|
};
|
|
160
161
|
|
|
162
|
+
function bindEntries(
|
|
163
|
+
container: Container,
|
|
164
|
+
{ singletons = [], instances = [] }: Pick<ProviderProps, 'singletons' | 'instances'>
|
|
165
|
+
) {
|
|
166
|
+
singletons.map(bindEntry(container, true)).forEach(binding => {
|
|
167
|
+
binding?.inSingletonScope();
|
|
168
|
+
});
|
|
169
|
+
instances.forEach(bindEntry(container, false));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function unbindEntries(
|
|
173
|
+
container: Container,
|
|
174
|
+
{ singletons = [], instances = [] }: Pick<ProviderProps, 'singletons' | 'instances'>
|
|
175
|
+
) {
|
|
176
|
+
[...singletons, ...instances].forEach(unbindEntry(container));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function initializeStores(stores: Store[], onError: (error: any) => void) {
|
|
180
|
+
const promises: Promise<void>[] = [];
|
|
181
|
+
|
|
182
|
+
for (const instance of stores) {
|
|
183
|
+
let promise;
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
promise = instance.initialize?.();
|
|
187
|
+
} catch (e: any) {
|
|
188
|
+
onError(e);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (promise && typeof promise.catch === 'function') {
|
|
192
|
+
promises.push(promise.catch(onError));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return promises;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function disposeStores(stores: Store[]) {
|
|
200
|
+
for (const instance of stores) {
|
|
201
|
+
instance.dispose?.();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
161
205
|
export type ProviderProps = PropsWithChildren<{
|
|
162
206
|
singletons?: ProviderConfigEntrySingletons<any>[];
|
|
163
207
|
instances?: ProviderConfigEntryInstances<any>[];
|
|
@@ -173,65 +217,31 @@ export const Provider: FC<ProviderProps> = ({
|
|
|
173
217
|
children,
|
|
174
218
|
}) => {
|
|
175
219
|
const parentContainer = useContext(ContainerContext);
|
|
176
|
-
|
|
177
220
|
const containerRef = useRef<Container>();
|
|
178
221
|
const [promises, setPromises] = useState<Promise<void>[]>([]);
|
|
179
222
|
const [error, setError] = useState(false);
|
|
180
223
|
|
|
181
|
-
|
|
224
|
+
useEffect(() => {
|
|
182
225
|
const container = new Container();
|
|
183
226
|
container.parent = parentContainer;
|
|
184
|
-
|
|
185
|
-
singletons?.map(bindEntry(container, true)).forEach(binding => {
|
|
186
|
-
binding?.inSingletonScope();
|
|
187
|
-
});
|
|
188
|
-
instances?.forEach(bindEntry(container, false));
|
|
189
|
-
|
|
190
|
-
const storeInstances = getStoreInstances(container, singletons, instances);
|
|
191
|
-
|
|
192
|
-
const promises: Promise<void>[] = [];
|
|
193
|
-
for (const instance of storeInstances) {
|
|
194
|
-
if (instance.initialize) {
|
|
195
|
-
let promise;
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
promise = instance.initialize();
|
|
199
|
-
} catch {
|
|
200
|
-
setError(true);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (promise && typeof promise.catch === 'function') {
|
|
204
|
-
promises.push(
|
|
205
|
-
promise.catch(() => {
|
|
206
|
-
setError(true);
|
|
207
|
-
})
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
227
|
containerRef.current = container;
|
|
228
|
+
|
|
229
|
+
bindEntries(container, { singletons, instances });
|
|
230
|
+
const promises = initializeStores(
|
|
231
|
+
getStoreInstances(container, { singletons, instances }),
|
|
232
|
+
() => setError(true)
|
|
233
|
+
);
|
|
214
234
|
setPromises(promises);
|
|
215
|
-
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
216
235
|
|
|
217
|
-
useEffect(() => {
|
|
218
236
|
return () => {
|
|
219
237
|
const container = containerRef.current;
|
|
220
238
|
if (!container) {
|
|
221
239
|
return;
|
|
222
240
|
}
|
|
223
241
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
singletons?.forEach(unbind);
|
|
228
|
-
instances?.forEach(unbind);
|
|
229
|
-
|
|
230
|
-
for (const instance of storeInstances) {
|
|
231
|
-
if (instance.dispose) {
|
|
232
|
-
instance.dispose();
|
|
233
|
-
}
|
|
234
|
-
}
|
|
242
|
+
unbindEntries(container, { singletons, instances });
|
|
243
|
+
disposeStores(getStoreInstances(container, { singletons, instances }));
|
|
244
|
+
setPromises([]);
|
|
235
245
|
};
|
|
236
246
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
237
247
|
|