@tramvai/state 1.71.1 → 1.73.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.
@@ -0,0 +1,30 @@
1
+ import type { Dispatcher } from './dispatcher';
2
+ import type { StoreClass } from '../typings';
3
+ import type { Middleware } from './dispatcher.h';
4
+ import { DispatcherContext } from './dispatcherContext';
5
+ declare type InitialState = {
6
+ stores: Record<string, any>;
7
+ };
8
+ export declare class ChildDispatcherContext<TContext> extends DispatcherContext<TContext> {
9
+ private parentDispatcherContext;
10
+ private allowedParentStores;
11
+ /**
12
+ * @param context The context to be used for store instances
13
+ */
14
+ constructor({ dispatcher, context, initialState, parentDispatcherContext, middlewares, parentAllowedStores, }: {
15
+ dispatcher: Dispatcher;
16
+ context: TContext;
17
+ initialState: InitialState;
18
+ middlewares?: Middleware[];
19
+ parentDispatcherContext: DispatcherContext<TContext>;
20
+ parentAllowedStores?: Array<StoreClass | string | {
21
+ store: StoreClass | string;
22
+ optional: true;
23
+ }>;
24
+ });
25
+ getStore<T extends StoreClass>(storeClass: T | string | {
26
+ store: T | string;
27
+ optional: true;
28
+ }): InstanceType<T> | null;
29
+ }
30
+ export {};
@@ -23,13 +23,14 @@ export declare class DispatcherContext<TContext> extends SimpleEmitter {
23
23
  };
24
24
  rehydratedStoreState: Record<string, any>;
25
25
  context: TContext;
26
- private fullState;
26
+ protected fullState: Record<string, any>;
27
27
  applyDispatch: <Payload>(event: Event<Payload>) => Payload;
28
28
  /**
29
29
  * @param context The context to be used for store instances
30
30
  */
31
31
  constructor(dispatcher: Dispatcher, context: TContext, initialState: InitialState, middlewares?: Middleware[]);
32
32
  applyMiddlewares(middlewares: Middleware[]): (...args: any[]) => never;
33
+ protected storeSubscribe(storeName: string, storeInstance: StoreInstance): void;
33
34
  /**
34
35
  * @deprecated
35
36
  *
package/lib/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as devTools from './devTools';
2
2
  export { Middleware } from './dispatcher/dispatcher.h';
3
3
  export { createDispatcher, Dispatcher } from './dispatcher/dispatcher';
4
4
  export { DispatcherContext, convertAction } from './dispatcher/dispatcherContext';
5
+ export { ChildDispatcherContext } from './dispatcher/childDispatcherContext';
5
6
  export { Event } from './createEvent/createEvent.h';
6
7
  export { Reducer } from './createReducer/createReducer.h';
7
8
  export { createEvent } from './createEvent/createEvent';
package/lib/index.es.js CHANGED
@@ -129,7 +129,7 @@ class DispatcherContext extends SimpleEmitter {
129
129
  if (initialState) {
130
130
  this.rehydrate(initialState);
131
131
  }
132
- if (middlewares) {
132
+ if (middlewares === null || middlewares === void 0 ? void 0 : middlewares.length) {
133
133
  this.applyDispatch = this.applyMiddlewares(middlewares);
134
134
  }
135
135
  // Инцииализируем уже имеющиеся сторы
@@ -149,6 +149,23 @@ class DispatcherContext extends SimpleEmitter {
149
149
  dispatch = compose(...middlewares.map((middleware) => middleware(api)))(this.applyDispatch);
150
150
  return dispatch;
151
151
  }
152
+ storeSubscribe(storeName, storeInstance) {
153
+ const subscribeHandler = () => {
154
+ const newState = storeInstance.getState();
155
+ if (newState !== this.fullState[storeName]) {
156
+ this.fullState = {
157
+ ...this.fullState,
158
+ [storeName]: newState,
159
+ };
160
+ this.emit('change');
161
+ }
162
+ };
163
+ subscribe(storeInstance, subscribeHandler);
164
+ const unsubscribe = () => {
165
+ storeInstance.off('change', subscribeHandler);
166
+ };
167
+ this.storeUnsubscribeCallbacks[storeName] = unsubscribe;
168
+ }
152
169
  // eslint-disable-next-line max-statements
153
170
  getStore(storeClass) {
154
171
  let storeClassPrepared;
@@ -184,21 +201,7 @@ class DispatcherContext extends SimpleEmitter {
184
201
  }
185
202
  this.rehydratedStoreState[storeName] = null;
186
203
  }
187
- const subscribeHandler = () => {
188
- const newState = storeInstance.getState();
189
- if (newState !== this.fullState[storeName]) {
190
- this.fullState = {
191
- ...this.fullState,
192
- [storeName]: newState,
193
- };
194
- this.emit('change');
195
- }
196
- };
197
- subscribe(storeInstance, subscribeHandler);
198
- const unsubscribe = () => {
199
- storeInstance.off('change', subscribeHandler);
200
- };
201
- this.storeUnsubscribeCallbacks[storeName] = unsubscribe;
204
+ this.storeSubscribe(storeName, storeInstance);
202
205
  // TODO: убрать после того отпадёт надобность связывать сторы router и application
203
206
  if (Store.dependencies) {
204
207
  Store.dependencies.forEach((dependencyStoreClass) => {
@@ -294,7 +297,7 @@ class DispatcherContext extends SimpleEmitter {
294
297
  if ('storeName' in args[0]) {
295
298
  const reducer = args[0];
296
299
  const callback = args[1];
297
- const reducerInstance = this.storeInstances[reducer.storeName];
300
+ const reducerInstance = this.getStore(reducer);
298
301
  const listener = () => {
299
302
  const state = this.getState(reducer);
300
303
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -445,6 +448,49 @@ function createDispatcher(options) {
445
448
  return new Dispatcher(options);
446
449
  }
447
450
 
451
+ class ChildDispatcherContext extends DispatcherContext {
452
+ /**
453
+ * @param context The context to be used for store instances
454
+ */
455
+ constructor({ dispatcher, context, initialState, parentDispatcherContext, middlewares, parentAllowedStores, }) {
456
+ super(dispatcher, context, initialState, middlewares);
457
+ this.allowedParentStores = new Set();
458
+ this.parentDispatcherContext = parentDispatcherContext;
459
+ parentAllowedStores === null || parentAllowedStores === void 0 ? void 0 : parentAllowedStores.forEach((store) => {
460
+ const storeName = this.dispatcher.getStoreName(typeof store === 'object' ? store.store : store);
461
+ this.allowedParentStores.add(storeName);
462
+ // use just storeName to prevent store initialization on the root-app side
463
+ this.getStore({ store: storeName, optional: true });
464
+ });
465
+ }
466
+ getStore(storeClass) {
467
+ let storeClassPrepared;
468
+ if (typeof storeClass === 'object') {
469
+ storeClassPrepared = storeClass.store;
470
+ }
471
+ else {
472
+ storeClassPrepared = storeClass;
473
+ }
474
+ const storeName = this.dispatcher.getStoreName(storeClassPrepared);
475
+ if (this.dispatcher.stores[storeName]) {
476
+ return super.getStore(storeClass);
477
+ }
478
+ if (this.allowedParentStores.has(storeName)) {
479
+ // use just storeName to prevent store initialization on the root-app side
480
+ const storeInstance = this.parentDispatcherContext.getStore({
481
+ store: storeName,
482
+ optional: true,
483
+ });
484
+ if (!storeInstance) {
485
+ return null;
486
+ }
487
+ this.storeSubscribe(storeName, storeInstance);
488
+ return storeInstance;
489
+ }
490
+ return super.getStore(storeClass);
491
+ }
492
+ }
493
+
448
494
  function createEvent(eventName, payloadCreator = identity) {
449
495
  if (process.env.NODE_ENV !== 'production') {
450
496
  if (!isString(eventName) || !eventName.length) {
@@ -1334,4 +1380,4 @@ function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories:
1334
1380
  const connect = /* @__PURE__ */ createConnect();
1335
1381
  const { Consumer } = ConnectContext;
1336
1382
 
1337
- export { BaseStore, Consumer, Dispatcher, DispatcherContext, Provider, Subscription, connect, convertAction, createConnect, createDispatcher, createEvent, createReducer, index as devTools, useActions, useConsumerContext, useIsomorphicLayoutEffect, useSelector, useStore, useStoreSelector };
1383
+ export { BaseStore, ChildDispatcherContext, Consumer, Dispatcher, DispatcherContext, Provider, Subscription, connect, convertAction, createConnect, createDispatcher, createEvent, createReducer, index as devTools, useActions, useConsumerContext, useIsomorphicLayoutEffect, useSelector, useStore, useStoreSelector };
package/lib/index.js CHANGED
@@ -152,7 +152,7 @@ class DispatcherContext extends SimpleEmitter {
152
152
  if (initialState) {
153
153
  this.rehydrate(initialState);
154
154
  }
155
- if (middlewares) {
155
+ if (middlewares === null || middlewares === void 0 ? void 0 : middlewares.length) {
156
156
  this.applyDispatch = this.applyMiddlewares(middlewares);
157
157
  }
158
158
  // Инцииализируем уже имеющиеся сторы
@@ -172,6 +172,23 @@ class DispatcherContext extends SimpleEmitter {
172
172
  dispatch = compose__default["default"](...middlewares.map((middleware) => middleware(api)))(this.applyDispatch);
173
173
  return dispatch;
174
174
  }
175
+ storeSubscribe(storeName, storeInstance) {
176
+ const subscribeHandler = () => {
177
+ const newState = storeInstance.getState();
178
+ if (newState !== this.fullState[storeName]) {
179
+ this.fullState = {
180
+ ...this.fullState,
181
+ [storeName]: newState,
182
+ };
183
+ this.emit('change');
184
+ }
185
+ };
186
+ subscribe(storeInstance, subscribeHandler);
187
+ const unsubscribe = () => {
188
+ storeInstance.off('change', subscribeHandler);
189
+ };
190
+ this.storeUnsubscribeCallbacks[storeName] = unsubscribe;
191
+ }
175
192
  // eslint-disable-next-line max-statements
176
193
  getStore(storeClass) {
177
194
  let storeClassPrepared;
@@ -207,21 +224,7 @@ class DispatcherContext extends SimpleEmitter {
207
224
  }
208
225
  this.rehydratedStoreState[storeName] = null;
209
226
  }
210
- const subscribeHandler = () => {
211
- const newState = storeInstance.getState();
212
- if (newState !== this.fullState[storeName]) {
213
- this.fullState = {
214
- ...this.fullState,
215
- [storeName]: newState,
216
- };
217
- this.emit('change');
218
- }
219
- };
220
- subscribe(storeInstance, subscribeHandler);
221
- const unsubscribe = () => {
222
- storeInstance.off('change', subscribeHandler);
223
- };
224
- this.storeUnsubscribeCallbacks[storeName] = unsubscribe;
227
+ this.storeSubscribe(storeName, storeInstance);
225
228
  // TODO: убрать после того отпадёт надобность связывать сторы router и application
226
229
  if (Store.dependencies) {
227
230
  Store.dependencies.forEach((dependencyStoreClass) => {
@@ -317,7 +320,7 @@ class DispatcherContext extends SimpleEmitter {
317
320
  if ('storeName' in args[0]) {
318
321
  const reducer = args[0];
319
322
  const callback = args[1];
320
- const reducerInstance = this.storeInstances[reducer.storeName];
323
+ const reducerInstance = this.getStore(reducer);
321
324
  const listener = () => {
322
325
  const state = this.getState(reducer);
323
326
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -468,6 +471,49 @@ function createDispatcher(options) {
468
471
  return new Dispatcher(options);
469
472
  }
470
473
 
474
+ class ChildDispatcherContext extends DispatcherContext {
475
+ /**
476
+ * @param context The context to be used for store instances
477
+ */
478
+ constructor({ dispatcher, context, initialState, parentDispatcherContext, middlewares, parentAllowedStores, }) {
479
+ super(dispatcher, context, initialState, middlewares);
480
+ this.allowedParentStores = new Set();
481
+ this.parentDispatcherContext = parentDispatcherContext;
482
+ parentAllowedStores === null || parentAllowedStores === void 0 ? void 0 : parentAllowedStores.forEach((store) => {
483
+ const storeName = this.dispatcher.getStoreName(typeof store === 'object' ? store.store : store);
484
+ this.allowedParentStores.add(storeName);
485
+ // use just storeName to prevent store initialization on the root-app side
486
+ this.getStore({ store: storeName, optional: true });
487
+ });
488
+ }
489
+ getStore(storeClass) {
490
+ let storeClassPrepared;
491
+ if (typeof storeClass === 'object') {
492
+ storeClassPrepared = storeClass.store;
493
+ }
494
+ else {
495
+ storeClassPrepared = storeClass;
496
+ }
497
+ const storeName = this.dispatcher.getStoreName(storeClassPrepared);
498
+ if (this.dispatcher.stores[storeName]) {
499
+ return super.getStore(storeClass);
500
+ }
501
+ if (this.allowedParentStores.has(storeName)) {
502
+ // use just storeName to prevent store initialization on the root-app side
503
+ const storeInstance = this.parentDispatcherContext.getStore({
504
+ store: storeName,
505
+ optional: true,
506
+ });
507
+ if (!storeInstance) {
508
+ return null;
509
+ }
510
+ this.storeSubscribe(storeName, storeInstance);
511
+ return storeInstance;
512
+ }
513
+ return super.getStore(storeClass);
514
+ }
515
+ }
516
+
471
517
  function createEvent(eventName, payloadCreator = identity__default["default"]) {
472
518
  if (process.env.NODE_ENV !== 'production') {
473
519
  if (!isString__default["default"](eventName) || !eventName.length) {
@@ -1358,6 +1404,7 @@ const connect = /* @__PURE__ */ createConnect();
1358
1404
  const { Consumer } = ConnectContext;
1359
1405
 
1360
1406
  exports.BaseStore = BaseStore;
1407
+ exports.ChildDispatcherContext = ChildDispatcherContext;
1361
1408
  exports.Consumer = Consumer;
1362
1409
  exports.Dispatcher = Dispatcher;
1363
1410
  exports.DispatcherContext = DispatcherContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/state",
3
- "version": "1.71.1",
3
+ "version": "1.73.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@tinkoff/react-hooks": "0.0.23",
22
22
  "@tinkoff/utils": "^2.1.2",
23
- "@tramvai/types-actions-state-context": "1.71.1",
23
+ "@tramvai/types-actions-state-context": "1.73.0",
24
24
  "@types/hoist-non-react-statics": "^3.3.1",
25
25
  "invariant": "^2.2.4",
26
26
  "react-is": ">=17",