@tramvai/state 2.70.0 → 2.72.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.
Files changed (67) hide show
  1. package/lib/connect/Provider.es.js +8 -0
  2. package/lib/connect/Provider.js +12 -0
  3. package/lib/connect/Subscription.es.js +37 -0
  4. package/lib/connect/Subscription.js +41 -0
  5. package/lib/connect/connectAdvanced.es.js +159 -0
  6. package/lib/connect/connectAdvanced.js +170 -0
  7. package/lib/connect/context.es.js +6 -0
  8. package/lib/connect/context.js +11 -0
  9. package/lib/connect/hooks/useActions.es.js +17 -0
  10. package/lib/connect/hooks/useActions.js +25 -0
  11. package/lib/connect/hooks/useConsumerContext.es.js +12 -0
  12. package/lib/connect/hooks/useConsumerContext.js +16 -0
  13. package/lib/connect/hooks/useSelector.es.js +53 -0
  14. package/lib/connect/hooks/useSelector.js +63 -0
  15. package/lib/connect/hooks/useStore.es.js +37 -0
  16. package/lib/connect/hooks/useStore.js +41 -0
  17. package/lib/connect/hooks/useStoreSelector.es.js +11 -0
  18. package/lib/connect/hooks/useStoreSelector.js +15 -0
  19. package/lib/connect/index.es.js +91 -0
  20. package/lib/connect/index.js +107 -0
  21. package/lib/connect/scheduling.es.js +12 -0
  22. package/lib/connect/scheduling.js +16 -0
  23. package/lib/connect/selectorFactory.es.js +95 -0
  24. package/lib/connect/selectorFactory.js +101 -0
  25. package/lib/connect/toProps/mapContextToProps.es.js +23 -0
  26. package/lib/connect/toProps/mapContextToProps.js +34 -0
  27. package/lib/connect/toProps/mapStateToProps.es.js +17 -0
  28. package/lib/connect/toProps/mapStateToProps.js +27 -0
  29. package/lib/connect/toProps/mergeProps.es.js +36 -0
  30. package/lib/connect/toProps/mergeProps.js +42 -0
  31. package/lib/connect/toProps/wrapMapToProps.es.js +73 -0
  32. package/lib/connect/toProps/wrapMapToProps.js +85 -0
  33. package/lib/connect/utils/verifyFunction.es.js +10 -0
  34. package/lib/connect/utils/verifyFunction.js +18 -0
  35. package/lib/connect/utils/verifyMapToProps.es.js +20 -0
  36. package/lib/connect/utils/verifyMapToProps.js +28 -0
  37. package/lib/connect/utils/verifyPlainObject.es.js +10 -0
  38. package/lib/connect/utils/verifyPlainObject.js +18 -0
  39. package/lib/createEvent/createEvent.es.js +22 -0
  40. package/lib/createEvent/createEvent.js +31 -0
  41. package/lib/createReducer/createReducer.es.js +60 -0
  42. package/lib/createReducer/createReducer.js +64 -0
  43. package/lib/devTools/constants.es.js +3 -0
  44. package/lib/devTools/constants.js +7 -0
  45. package/lib/{index_middleware.es.js → devTools/devTools.es.js} +2 -36
  46. package/lib/{index_middleware.js → devTools/devTools.js} +4 -40
  47. package/lib/devTools/index.es.js +21 -0
  48. package/lib/devTools/index.js +23 -0
  49. package/lib/devTools/middleware.es.js +37 -0
  50. package/lib/devTools/middleware.js +45 -0
  51. package/lib/dispatcher/childDispatcherContext.es.js +46 -0
  52. package/lib/dispatcher/childDispatcherContext.js +50 -0
  53. package/lib/dispatcher/dispatcher.es.js +105 -0
  54. package/lib/dispatcher/dispatcher.js +110 -0
  55. package/lib/dispatcher/dispatcherContext.es.js +279 -0
  56. package/lib/dispatcher/dispatcherContext.js +288 -0
  57. package/lib/dispatcher/storeSubscribe.es.js +8 -0
  58. package/lib/dispatcher/storeSubscribe.js +12 -0
  59. package/lib/index.es.js +16 -1246
  60. package/lib/index.js +36 -1281
  61. package/lib/logger.es.js +3 -0
  62. package/lib/logger.js +7 -0
  63. package/lib/stores/BaseStore.es.js +53 -0
  64. package/lib/stores/BaseStore.js +61 -0
  65. package/lib/stores/SimpleEmitter.es.js +30 -0
  66. package/lib/stores/SimpleEmitter.js +34 -0
  67. package/package.json +6 -7
package/lib/index.es.js CHANGED
@@ -1,1247 +1,17 @@
1
- import compose from '@tinkoff/utils/function/compose';
2
- import isString from '@tinkoff/utils/is/string';
3
- import identity from '@tinkoff/utils/function/identity';
4
- import pick from '@tinkoff/utils/object/pick';
5
- import shallowEqual from '@tinkoff/utils/is/shallowEqual';
6
- import strictEqual from '@tinkoff/utils/is/strictEqual';
7
- import { jsx } from 'react/jsx-runtime';
8
- import noop from '@tinkoff/utils/function/noop';
9
- import hoistStatics from 'hoist-non-react-statics';
10
- import invariant from 'invariant';
11
- import React, { createContext, useContext, useMemo, useRef, useCallback } from 'react';
12
- import { isValidElementType } from 'react-is';
13
- import { useSyncExternalStore } from 'use-sync-external-store/shim';
14
- import isArray from '@tinkoff/utils/is/array';
15
- import { useShallowEqual, useIsomorphicLayoutEffect } from '@tinkoff/react-hooks';
1
+ import * as index from './devTools/index.es.js';
2
+ export { index as devTools };
3
+ export { Dispatcher, createDispatcher } from './dispatcher/dispatcher.es.js';
4
+ export { DispatcherContext, convertAction } from './dispatcher/dispatcherContext.es.js';
5
+ export { ChildDispatcherContext } from './dispatcher/childDispatcherContext.es.js';
6
+ export { createEvent } from './createEvent/createEvent.es.js';
7
+ export { createReducer } from './createReducer/createReducer.es.js';
8
+ export { BaseStore } from './stores/BaseStore.es.js';
9
+ export { Consumer, default as connect, createConnect } from './connect/index.es.js';
10
+ export { Subscription } from './connect/Subscription.es.js';
11
+ export { Provider } from './connect/Provider.es.js';
12
+ export { useConsumerContext } from './connect/hooks/useConsumerContext.es.js';
13
+ export { useActions } from './connect/hooks/useActions.es.js';
14
+ export { useStore } from './connect/hooks/useStore.es.js';
15
+ export { useSelector } from './connect/hooks/useSelector.es.js';
16
+ export { useStoreSelector } from './connect/hooks/useStoreSelector.es.js';
16
17
  export { useIsomorphicLayoutEffect } from '@tinkoff/react-hooks';
17
- import toArray from '@tinkoff/utils/array/toArray';
18
- import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector';
19
- import always from '@tinkoff/utils/function/always';
20
- import mapObject from '@tinkoff/utils/object/map';
21
- import isPlainObject from '@tinkoff/utils/is/plainObject';
22
- import isFunction from '@tinkoff/utils/is/function';
23
-
24
- /*
25
- ### TODO
26
-
27
- Монорепозиторий экосистемы [redux-devtools](https://github.com/reduxjs/redux-devtools)
28
-
29
- Пример кастомной [интеграции redux-devtools с mobx](https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js)
30
-
31
- Интегрированный в DevTools функционал:
32
-
33
- 1. Лог экшенов
34
- 2. Состояние стейта
35
- 3. Dispatch
36
- 4. ~~Time Traveling~~
37
- */
38
- // eslint-disable-next-line import/no-mutable-exports
39
- let middleware = () => () => (next) => (event) => next(event);
40
- if (process.env.NODE_ENV !== 'production') {
41
- middleware = require('./index_middleware.es.js').middleware;
42
- }
43
-
44
- var index = {
45
- __proto__: null,
46
- get middleware () { return middleware; }
47
- };
48
-
49
- const subscribe = (store, handler) => {
50
- // подписываемся на изменения
51
- store.on('change', handler);
52
- // вызываем сразу, чтобы заполнить начальное состояние
53
- handler();
54
- };
55
-
56
- class SimpleEmitter {
57
- constructor() {
58
- this.listeners = [];
59
- }
60
- emit(name) {
61
- this.listeners.forEach((listener) => {
62
- listener();
63
- });
64
- }
65
- addListener(event, fn) {
66
- this.listeners.push(fn);
67
- }
68
- on(event, fn) {
69
- this.addListener(event, fn);
70
- }
71
- removeListener(event, fn) {
72
- const listeners = [];
73
- for (let i = 0; i < this.listeners.length; i++) {
74
- if (this.listeners[i] !== fn) {
75
- listeners.push(this.listeners[i]);
76
- }
77
- }
78
- this.listeners = listeners;
79
- }
80
- off(event, fn) {
81
- this.removeListener(event, fn);
82
- }
83
- }
84
-
85
- const eventExecutor = (event, handlerFns) => {
86
- const keys = Object.keys(handlerFns);
87
- for (let index = 0; index < keys.length; index++) {
88
- const storeName = keys[index];
89
- const handlerFn = handlerFns[storeName];
90
- if (!handlerFn) {
91
- throw new Error(`${storeName} does not have a handler for action ${event.type}`);
92
- }
93
- handlerFn(event.payload, event.type);
94
- }
95
- };
96
- // Конвертация старого типа экшенов в новый
97
- const convertAction = (actionOrNameEvent, payload) => {
98
- if (typeof actionOrNameEvent === 'string') {
99
- return {
100
- payload,
101
- type: actionOrNameEvent,
102
- error: false,
103
- };
104
- }
105
- return actionOrNameEvent;
106
- };
107
- // Это форкнутый вариант dispatchr
108
- class DispatcherContext extends SimpleEmitter {
109
- /**
110
- * @param context The context to be used for store instances
111
- */
112
- constructor(dispatcher, context, initialState, middlewares) {
113
- super();
114
- this.applyDispatch = (event) => {
115
- const eventHandlers = this.dispatcher.handlers[event.type] || [];
116
- if (!eventHandlers.length) {
117
- if (process.env.NODE_ENV === 'development') {
118
- console.warn(`
119
- The event "${event.type}" has been dispatched, but no reducers for this event were registered.
120
- Have you forgot to register reducer or add event handler in existing reducer?
121
- `);
122
- }
123
- return event.payload;
124
- }
125
- this.applyHandlers(event, eventHandlers);
126
- return event.payload;
127
- };
128
- this.dispatcher = dispatcher;
129
- this.storeInstances = {};
130
- this.storeUnsubscribeCallbacks = {};
131
- this.context = context;
132
- this.dispatcherInterface = {
133
- getContext: () => this.context,
134
- getStore: this.getStore.bind(this),
135
- };
136
- this.rehydratedStoreState = {};
137
- this.fullState = {};
138
- // Заполняем стейт данными
139
- if (initialState) {
140
- this.rehydrate(initialState);
141
- }
142
- if (middlewares === null || middlewares === void 0 ? void 0 : middlewares.length) {
143
- this.applyDispatch = this.applyMiddlewares(middlewares);
144
- }
145
- // Инцииализируем уже имеющиеся сторы
146
- Object.keys(this.dispatcher.stores).forEach((store) => {
147
- this.getStore(store);
148
- });
149
- }
150
- applyMiddlewares(middlewares) {
151
- let dispatch = (...args) => {
152
- throw new Error('Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch.');
153
- };
154
- const api = {
155
- getState: this.getState.bind(this),
156
- subscribe: this.subscribe.bind(this),
157
- dispatch: (...args) => dispatch(...args),
158
- };
159
- dispatch = compose(...middlewares.map((middleware) => middleware(api)))(this.applyDispatch);
160
- return dispatch;
161
- }
162
- storeSubscribe(storeName, storeInstance) {
163
- const subscribeHandler = () => {
164
- const newState = storeInstance.getState();
165
- if (newState !== this.fullState[storeName]) {
166
- this.fullState = {
167
- ...this.fullState,
168
- [storeName]: newState,
169
- };
170
- this.emit('change');
171
- }
172
- };
173
- subscribe(storeInstance, subscribeHandler);
174
- const unsubscribe = () => {
175
- storeInstance.off('change', subscribeHandler);
176
- };
177
- this.storeUnsubscribeCallbacks[storeName] = unsubscribe;
178
- }
179
- // eslint-disable-next-line max-statements
180
- getStore(storeClass) {
181
- let storeClassPrepared;
182
- let optional = false;
183
- if (typeof storeClass === 'object') {
184
- storeClassPrepared = storeClass.store;
185
- optional = storeClass.optional;
186
- }
187
- else {
188
- storeClassPrepared = storeClass;
189
- }
190
- const storeName = this.dispatcher.getStoreName(storeClassPrepared);
191
- if (!this.storeInstances[storeName]) {
192
- let Store = this.dispatcher.stores[storeName];
193
- if (!Store) {
194
- if (typeof storeClassPrepared === 'function') {
195
- this.dispatcher.registerStore(storeClassPrepared);
196
- Store = storeClassPrepared;
197
- }
198
- else {
199
- if (optional) {
200
- return null;
201
- }
202
- throw new Error(`Store ${storeName} was not registered.`);
203
- }
204
- }
205
- const storeInstance = new Store(this.dispatcherInterface);
206
- this.storeInstances[storeName] = storeInstance;
207
- if (this.rehydratedStoreState && this.rehydratedStoreState[storeName]) {
208
- const state = this.rehydratedStoreState[storeName];
209
- if (storeInstance.rehydrate) {
210
- storeInstance.rehydrate(state);
211
- }
212
- this.rehydratedStoreState[storeName] = null;
213
- }
214
- this.storeSubscribe(storeName, storeInstance);
215
- // TODO: убрать после того отпадёт надобность связывать сторы router и application
216
- if (Store.dependencies) {
217
- Store.dependencies.forEach((dependencyStoreClass) => {
218
- const dependency = this.getStore(dependencyStoreClass);
219
- subscribe(dependency, () => {
220
- storeInstance.emit('change');
221
- });
222
- });
223
- }
224
- }
225
- return this.storeInstances[storeName];
226
- }
227
- /**
228
- * Dispatches a new action or throws if one is already in progress
229
- * @param eventOrType Name of the event to be dispatched
230
- * @param payload Parameters to describe the action
231
- * @throws {Error} if store has handler registered that does not exist
232
- */
233
- dispatch(eventOrType, payload) {
234
- if (!eventOrType) {
235
- throw new Error(`eventOrType parameter ${eventOrType} is invalid.`);
236
- }
237
- // конвертим старый тип экшенов
238
- const event = convertAction(eventOrType, payload);
239
- return this.applyDispatch(event);
240
- }
241
- applyHandlers(action, handlers) {
242
- const handlerFns = {};
243
- const storeInstanceGet = (store) => {
244
- if (handlerFns[store.name]) {
245
- // Don't call the default if the store has an explicit action handler
246
- return;
247
- }
248
- const storeInstance = this.getStore(store.name);
249
- if (!storeInstance) {
250
- return;
251
- }
252
- if (typeof store.handler === 'function') {
253
- handlerFns[store.name] = store.handler.bind(storeInstance);
254
- }
255
- else {
256
- if (process.env.NODE_ENV !== 'production') {
257
- if (!storeInstance[store.handler]) {
258
- throw new Error(`${store.name} does not have a method called ${store.handler}`);
259
- }
260
- }
261
- handlerFns[store.name] = storeInstance[store.handler].bind(storeInstance);
262
- }
263
- };
264
- const handlersLength = handlers.length;
265
- for (let index = 0; index < handlersLength; index++) {
266
- storeInstanceGet(handlers[index]);
267
- }
268
- return eventExecutor(action, handlerFns);
269
- }
270
- /**
271
- * Returns a raw data object representation of the current state of the
272
- * dispatcher and all store instances. If the store implements a shouldDehdyrate
273
- * function, then it will be called and only dehydrate if the method returns `true`
274
- * @method dehydrate
275
- * @returns dehydrated dispatcher data
276
- */
277
- dehydrate() {
278
- const stores = {};
279
- const keys = Object.keys(this.storeInstances);
280
- for (let i = 0; i < keys.length; i++) {
281
- const storeName = keys[i];
282
- const store = this.storeInstances[storeName];
283
- if (!store.dehydrate()) {
284
- continue;
285
- }
286
- stores[storeName] = store.dehydrate();
287
- }
288
- return {
289
- stores,
290
- };
291
- }
292
- /**
293
- * Takes a raw data object and rehydrates the dispatcher and store instances
294
- * @method rehydrate
295
- * @param dispatcherState raw state typically retrieved from `dehydrate` method
296
- */
297
- rehydrate(dispatcherState) {
298
- if (dispatcherState.stores) {
299
- const keys = Object.keys(dispatcherState.stores);
300
- for (let index = 0; index < keys.length; index++) {
301
- const storeName = keys[index];
302
- this.rehydratedStoreState[storeName] = dispatcherState.stores[storeName];
303
- }
304
- }
305
- }
306
- subscribe(...args) {
307
- if ('storeName' in args[0]) {
308
- const reducer = args[0];
309
- const callback = args[1];
310
- const reducerInstance = this.getStore(reducer);
311
- const listener = () => {
312
- const state = this.getState(reducer);
313
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
314
- callback(state);
315
- };
316
- reducerInstance.on('change', listener);
317
- return () => {
318
- reducerInstance.off('change', listener);
319
- };
320
- }
321
- const callback = args[0];
322
- const listener = () => {
323
- const state = this.getState();
324
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
325
- callback(state);
326
- };
327
- this.on('change', listener);
328
- return () => {
329
- this.off('change', listener);
330
- };
331
- }
332
- getState(reducer) {
333
- if (reducer) {
334
- return this.fullState[reducer.storeName];
335
- }
336
- return this.fullState;
337
- }
338
- // Для отложенной инициализации контекста, в будующем нужно удалить
339
- setContext(context) {
340
- this.context = context;
341
- }
342
- hasStore(store) {
343
- return store.storeName in this.storeInstances && this.dispatcher.hasStore(store);
344
- }
345
- registerStore(store) {
346
- this.dispatcher.registerStore(store);
347
- this.getStore(store);
348
- }
349
- unregisterStore(store) {
350
- const { storeName } = store;
351
- this.dispatcher.unregisterStore(store);
352
- this.storeUnsubscribeCallbacks[storeName]();
353
- delete this.storeUnsubscribeCallbacks[storeName];
354
- delete this.rehydratedStoreState[storeName];
355
- delete this.storeInstances[storeName];
356
- }
357
- }
358
-
359
- class Dispatcher {
360
- /**
361
- * @class Dispatcher
362
- * @param options Dispatcher options
363
- * @param options.stores Array of stores to register
364
- * @constructor
365
- */
366
- constructor(options) {
367
- // eslint-disable-next-line no-param-reassign
368
- options = options || {};
369
- // eslint-disable-next-line no-param-reassign
370
- options.stores = options.stores || [];
371
- this.stores = {};
372
- this.handlers = {};
373
- options.stores.forEach((store) => {
374
- this.registerStore(store);
375
- });
376
- }
377
- createContext(context, initialState, middlewares) {
378
- return new DispatcherContext(this, context, initialState, middlewares);
379
- }
380
- hasStore(store) {
381
- return !!this.stores[store.storeName];
382
- }
383
- /**
384
- * Registers a store so that it can handle actions.ß
385
- * @param store A store class to be registered. The store should have a static
386
- * `storeName` property so that it can be loaded later.
387
- * @throws {Error} if store is invalid
388
- * @throws {Error} if store is already registered
389
- */
390
- registerStore(store) {
391
- const { storeName } = store;
392
- if (this.stores[storeName]) {
393
- if (this.stores[storeName] === store) {
394
- // Store is already registered, nothing to do
395
- return;
396
- }
397
- if (process.env.NODE_ENV !== 'production') {
398
- throw new Error(`Store with name '${storeName}' has already been registered.
399
- Make sure you do not have multiple copies of the store installed.
400
- exist ${this.stores[storeName]}
401
- try ${store}`);
402
- }
403
- }
404
- this.stores[storeName] = store;
405
- if (store.handlers) {
406
- Object.keys(store.handlers).forEach((action) => {
407
- const handler = store.handlers[action];
408
- this.registerHandler(action, storeName, handler);
409
- });
410
- }
411
- }
412
- unregisterStore(store) {
413
- const { storeName } = store;
414
- if (!this.stores[storeName]) {
415
- return;
416
- }
417
- delete this.stores[storeName];
418
- if (store.handlers) {
419
- Object.keys(store.handlers).forEach((action) => {
420
- const handler = store.handlers[action];
421
- this.unregisterHandler(action, storeName, handler);
422
- });
423
- }
424
- }
425
- /**
426
- * Gets a name from a store
427
- * @param {String|Object} store The store name or class from which to extract
428
- */
429
- // eslint-disable-next-line class-methods-use-this
430
- getStoreName(store) {
431
- if (typeof store === 'string') {
432
- return store;
433
- }
434
- return store.storeName;
435
- }
436
- /**
437
- * Adds a handler function to be called for the given action
438
- * @param action Name of the action
439
- * @param name Name of the store that handles the action
440
- * @param handler The function or name of the method that handles the action
441
- */
442
- registerHandler(action, name, handler) {
443
- this.handlers[action] = this.handlers[action] || [];
444
- this.handlers[action].push({
445
- name,
446
- handler,
447
- });
448
- }
449
- unregisterHandler(action, name, handler) {
450
- if (Array.isArray(this.handlers[action])) {
451
- this.handlers[action] = this.handlers[action].filter((actionHandlers) => {
452
- return !(actionHandlers.name === name && actionHandlers.handler === handler);
453
- });
454
- }
455
- }
456
- }
457
- function createDispatcher(options) {
458
- return new Dispatcher(options);
459
- }
460
-
461
- class ChildDispatcherContext extends DispatcherContext {
462
- /**
463
- * @param context The context to be used for store instances
464
- */
465
- constructor({ dispatcher, context, initialState, parentDispatcherContext, middlewares, parentAllowedStores, }) {
466
- super(dispatcher, context, initialState, middlewares);
467
- this.allowedParentStores = new Set();
468
- this.parentDispatcherContext = parentDispatcherContext;
469
- parentAllowedStores === null || parentAllowedStores === void 0 ? void 0 : parentAllowedStores.forEach((store) => {
470
- const storeName = this.dispatcher.getStoreName(typeof store === 'object' ? store.store : store);
471
- this.allowedParentStores.add(storeName);
472
- // use just storeName to prevent store initialization on the root-app side
473
- this.getStore({ store: storeName, optional: true });
474
- });
475
- }
476
- getStore(storeClass) {
477
- let storeClassPrepared;
478
- if (typeof storeClass === 'object') {
479
- storeClassPrepared = storeClass.store;
480
- }
481
- else {
482
- storeClassPrepared = storeClass;
483
- }
484
- const storeName = this.dispatcher.getStoreName(storeClassPrepared);
485
- if (this.dispatcher.stores[storeName]) {
486
- return super.getStore(storeClass);
487
- }
488
- if (this.allowedParentStores.has(storeName)) {
489
- // use just storeName to prevent store initialization on the root-app side
490
- const storeInstance = this.parentDispatcherContext.getStore({
491
- store: storeName,
492
- optional: true,
493
- });
494
- if (!storeInstance) {
495
- return null;
496
- }
497
- this.storeSubscribe(storeName, storeInstance);
498
- return storeInstance;
499
- }
500
- return super.getStore(storeClass);
501
- }
502
- }
503
-
504
- function createEvent(eventName, payloadCreator = identity) {
505
- if (process.env.NODE_ENV !== 'production') {
506
- if (!isString(eventName) || !eventName.length) {
507
- throw new Error(`eventName should be not empty string, got '${eventName}'`);
508
- }
509
- }
510
- const type = eventName;
511
- const eventCreator = (...args) => {
512
- return {
513
- type,
514
- payload: payloadCreator(...args),
515
- };
516
- };
517
- eventCreator.getType = () => type;
518
- eventCreator.toString = () => type;
519
- return eventCreator;
520
- }
521
-
522
- function createReducer(name, initialState) {
523
- var _a;
524
- const reducers = {};
525
- return _a = class ReducerStore extends SimpleEmitter {
526
- constructor() {
527
- super();
528
- this.state = initialState;
529
- }
530
- static createEvents(model) {
531
- const eventNames = Object.keys(model);
532
- const events = {};
533
- eventNames.forEach((eventName) => {
534
- const handler = model[eventName];
535
- const eventCreator = createEvent(`${eventName}`);
536
- events[eventName] = eventCreator;
537
- ReducerStore.on(eventCreator, handler);
538
- });
539
- return events;
540
- }
541
- static on(eventOrType, reducer) {
542
- if (Array.isArray(eventOrType)) {
543
- eventOrType.forEach((event) => ReducerStore.on(event, reducer));
544
- return ReducerStore;
545
- }
546
- const type = eventOrType.toString();
547
- ReducerStore.handlers[type] = 'handle';
548
- reducers[type] = reducer;
549
- return ReducerStore;
550
- }
551
- getState() {
552
- return this.state;
553
- }
554
- setState(state) {
555
- this.state = state;
556
- // обновление необходимо, иначе state-manager не пересчитает состояние
557
- this.emit('change');
558
- }
559
- dehydrate() {
560
- return this.state;
561
- }
562
- rehydrate(state) {
563
- this.state = state;
564
- }
565
- handle(payload, eventName) {
566
- const reducer = reducers[eventName];
567
- if (reducer) {
568
- this.state = reducer(this.state, payload);
569
- this.emit('change');
570
- }
571
- }
572
- },
573
- _a.storeName = name,
574
- _a.handlers = {},
575
- _a;
576
- }
577
-
578
- /**
579
- * @deprecated метод устарел, в замен этого API используй createReducer, который новее и лучше маштабируется
580
- */
581
- class BaseStore extends SimpleEmitter {
582
- constructor() {
583
- super(...arguments);
584
- this.state = Object.create(null);
585
- this.hydrateKeys = Object.create(null);
586
- }
587
- getState() {
588
- return this.state;
589
- }
590
- dehydrate() {
591
- return pick(Object.keys(this.hydrateKeys), this.state);
592
- }
593
- rehydrate(state) {
594
- this.setStateSilently(state);
595
- }
596
- writeHydrateKeys(state) {
597
- Object.keys(state).forEach((key) => {
598
- this.hydrateKeys[key] = true;
599
- });
600
- }
601
- // eslint-disable-next-line class-methods-use-this
602
- shouldStateUpdate(nextState) {
603
- return !!Object.keys(nextState).length;
604
- }
605
- setState(state, force = false) {
606
- if (force || this.shouldStateUpdate(state)) {
607
- this.setStateSilently(state);
608
- this.emit('change');
609
- }
610
- }
611
- setStateSilently(state) {
612
- this.state = { ...this.state, ...state };
613
- this.writeHydrateKeys(state);
614
- }
615
- replaceState(state) {
616
- this.replaceStateSilently(state);
617
- this.emit('change');
618
- }
619
- // @deprecated нужно использовать replaceState
620
- replaceStateSilently(state) {
621
- this.state = state;
622
- this.hydrateKeys = Object.create(null);
623
- this.writeHydrateKeys(state);
624
- }
625
- }
626
-
627
- // encapsulates the subscription logic for connecting a component to the redux store, as
628
- // well as nesting subscriptions of descendant components, so that we can ensure the
629
- // ancestor components re-render before descendants
630
- class Subscription {
631
- constructor(stores) {
632
- this.handleStateChange = () => {
633
- this.onStateChange && this.onStateChange();
634
- };
635
- this.stores = stores;
636
- this.unsubscribe = undefined;
637
- }
638
- isSubscribed() {
639
- return Boolean(this.unsubscribe);
640
- }
641
- setOnStateChange(onStateChange) {
642
- this.onStateChange = onStateChange;
643
- }
644
- trySubscribe() {
645
- if (!this.unsubscribe) {
646
- this.unsubscribe = this.stores.filter(Boolean).map((store) => {
647
- store.on('change', this.handleStateChange);
648
- return () => {
649
- store.removeListener('change', this.handleStateChange);
650
- };
651
- });
652
- }
653
- }
654
- tryUnsubscribe() {
655
- if (this.unsubscribe) {
656
- this.unsubscribe.forEach((f) => f());
657
- this.unsubscribe = undefined;
658
- }
659
- this.onStateChange = undefined;
660
- }
661
- }
662
-
663
- const ConnectContext = /* #__PURE__*/ createContext(null);
664
- const ServerStateContext = /* #__PURE__*/ createContext(null);
665
-
666
- const useConsumerContext = () => {
667
- const context = useContext(ConnectContext);
668
- if (!context) {
669
- throw new Error('CONSUMER_CONTEXT not found, have you added "@tramvai/module-common"?');
670
- }
671
- return context;
672
- };
673
-
674
- function useActions(actions) {
675
- const context = useConsumerContext();
676
- const actionsRef = useShallowEqual(actions);
677
- return useMemo(() => {
678
- if (isArray(actionsRef)) {
679
- return actionsRef.map((action) => context.executeAction.bind(context, action));
680
- }
681
- return context.executeAction.bind(context, actionsRef);
682
- }, [actionsRef, context]);
683
- }
684
-
685
- function useStore(reducer) {
686
- const context = useConsumerContext();
687
- const serverState = useContext(ServerStateContext);
688
- const reducerRef = useRef(reducer);
689
- const addedReducerRef = useRef(null);
690
- // если текущий редьюсер не зарегистрирован в диспетчере,
691
- // регистрируем его вручную, что бы гарантировать работоспособность `context.getState(reducer)`,
692
- // и сохраняем в `addedReducerRef`, что бы удалить при unmount
693
- if (!context.hasStore(reducer)) {
694
- context.registerStore(reducer);
695
- addedReducerRef.current = reducer.storeName;
696
- }
697
- const subscribe = useCallback((reactUpdate) => {
698
- const unsubscribe = context.subscribe(reducer, reactUpdate);
699
- // заменяем текущий редьюсер
700
- reducerRef.current = reducer;
701
- return () => {
702
- // гарантируем отписку от обновлений текущего редьюсера,
703
- // при анмаунте компонента
704
- unsubscribe();
705
- // если текущий редьюсер был зарегистрирован в диспетчере в этом хуке,
706
- // удаляем его из диспетчера
707
- if (addedReducerRef.current) {
708
- context.unregisterStore(reducerRef.current);
709
- addedReducerRef.current = null;
710
- }
711
- };
712
- }, [reducer, context]);
713
- return useSyncExternalStore(subscribe, () => context.getState(reducer), serverState ? () => serverState[reducer.storeName] : () => context.getState(reducer));
714
- }
715
-
716
- const contextExecution = typeof window !== 'undefined' ? window : global;
717
- function scheduling() {
718
- if ('requestAnimationFrame' in contextExecution) {
719
- return requestAnimationFrame;
720
- }
721
- if ('setImmediate' in contextExecution) {
722
- return contextExecution.setImmediate;
723
- }
724
- return setTimeout;
725
- }
726
-
727
- const schedule = /* #__PURE__*/ scheduling();
728
- function useSelector(storesOrStore, selector, equalityFn = shallowEqual) {
729
- invariant(selector, `You must pass a selector to useSelectors`);
730
- const context = useConsumerContext();
731
- const serverState = useContext(ServerStateContext);
732
- const renderIsScheduled = useRef(false);
733
- const storesRef = useShallowEqual(storesOrStore);
734
- const subscription = useMemo(() => new Subscription(toArray(storesRef).map(context.getStore)), [storesRef, context]);
735
- const latestSubscriptionCallbackError = useRef();
736
- const subscribe = useCallback((reactUpdate) => {
737
- subscription.setOnStateChange(() => {
738
- if (!renderIsScheduled.current) {
739
- renderIsScheduled.current = true;
740
- schedule(() => {
741
- reactUpdate();
742
- renderIsScheduled.current = false;
743
- });
744
- }
745
- });
746
- subscription.trySubscribe();
747
- return () => {
748
- return subscription.tryUnsubscribe();
749
- };
750
- }, [subscription]);
751
- let selectedState;
752
- try {
753
- selectedState = useSyncExternalStoreWithSelector(subscribe, context.getState, serverState ? () => serverState : context.getState, selector, equalityFn);
754
- }
755
- catch (err) {
756
- let errorMessage = `An error occured while selecting the store state: ${err.message}.`;
757
- if (latestSubscriptionCallbackError.current) {
758
- errorMessage += `\nThe error may be correlated with this previous error:\n${latestSubscriptionCallbackError.current.stack}\n\nOriginal stack trace:`;
759
- }
760
- throw new Error(errorMessage);
761
- }
762
- useIsomorphicLayoutEffect(() => {
763
- latestSubscriptionCallbackError.current = undefined;
764
- });
765
- return selectedState;
766
- }
767
-
768
- const useStoreSelector = (store, selector) => {
769
- const memoizedSelector = useCallback((stores) => {
770
- return selector(stores[store.storeName]);
771
- }, [store, selector]);
772
- return useSelector(store, memoizedSelector);
773
- };
774
-
775
- const stringifyComponent = (Comp) => {
776
- try {
777
- return JSON.stringify(Comp);
778
- }
779
- catch (err) {
780
- return String(Comp);
781
- }
782
- };
783
- /**
784
- * @deprecated
785
- */
786
- function connectAdvanced(
787
- /*
788
- selectorFactory is a func that is responsible for returning the selector function used to
789
- compute new props from state, props, and dispatch. For example:
790
- export default connectAdvanced((dispatch, options) => (state, props) => ({
791
- thing: state.things[props.thingId],
792
- saveThing: fields => dispatch(actionCreators.saveThing(props.thingId, fields)),
793
- }))(YourComponent)
794
- Access to dispatch is provided to the factory so selectorFactories can bind actionCreators
795
- outside of their selector as an optimization. Options passed to connectAdvanced are passed to
796
- the selectorFactory, along with displayName and WrappedComponent, as the second argument.
797
- Note that selectorFactory is responsible for all caching/memoization of inbound and outbound
798
- props. Do not use connectAdvanced directly without memoizing results between calls to your
799
- selector, otherwise the Connect component will re-render on every state or props change.
800
- */
801
- selectorFactory,
802
- // options object:
803
- {
804
- // the func used to compute this HOC's displayName from the wrapped component's displayName.
805
- // probably overridden by wrapper functions such as connect()
806
- getDisplayName = (name) => `ConnectAdvanced(${name})`,
807
- // shown in error messages
808
- // probably overridden by wrapper functions such as connect()
809
- methodName = 'connectAdvanced',
810
- // stores to connect to
811
- stores = [],
812
- // determines whether this HOC subscribes to store changes
813
- shouldHandleStateChanges = true,
814
- // use React's forwardRef to expose a ref of the wrapped component
815
- forwardRef = false,
816
- // function used to schedule updates
817
- schedule = (fn) => fn(),
818
- // is component and all toProps functions are pure, so they can be memoized
819
- pure = true,
820
- // additional options are passed through to the selectorFactory
821
- ...connectOptions } = {}) {
822
- return function wrapWithConnect(WrappedComponent) {
823
- if (process.env.NODE_ENV !== 'production') {
824
- invariant(isValidElementType(WrappedComponent), `You must pass a component to the function returned by ` +
825
- `${methodName}. Instead received ${stringifyComponent(WrappedComponent)}`);
826
- }
827
- const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
828
- const displayName = getDisplayName(wrappedComponentName);
829
- const selectorFactoryOptions = {
830
- ...connectOptions,
831
- pure,
832
- getDisplayName,
833
- methodName,
834
- shouldHandleStateChanges,
835
- displayName,
836
- wrappedComponentName,
837
- WrappedComponent,
838
- };
839
- const ConnectFunction = (props) => {
840
- const [forwardedRef, wrapperProps] = useMemo(() => {
841
- // Distinguish between actual "data" props that were passed to the wrapper component,
842
- // and values needed to control behavior (forwarded refs, alternate context instances).
843
- // To maintain the wrapperProps object reference, memoize this destructuring.
844
- // eslint-disable-next-line no-shadow
845
- const { forwardedRef, ...wrapperProps } = props;
846
- return [forwardedRef, wrapperProps];
847
- }, [props]);
848
- // Retrieve the store and ancestor subscription via context, if available
849
- const contextValue = useConsumerContext();
850
- const serverState = useContext(ServerStateContext);
851
- invariant(Boolean(contextValue), `Could not find context in ` +
852
- `"${displayName}". Either wrap the root component in a <Provider>, ` +
853
- `or pass a custom React context provider to <Provider> and the corresponding ` +
854
- `React context consumer to ${displayName} in connect options.`);
855
- const childPropsSelector = useMemo(() => {
856
- // The child props selector needs the store reference as an input.
857
- // Re-create this selector whenever the store changes.
858
- return selectorFactory(contextValue, selectorFactoryOptions);
859
- }, [contextValue]);
860
- const subscription = useMemo(() => {
861
- if (!shouldHandleStateChanges)
862
- return null;
863
- return new Subscription(stores.map((store) => contextValue.getStore(store)));
864
- }, [contextValue]);
865
- useMemo(() => {
866
- if (subscription && typeof window !== 'undefined') {
867
- subscription.trySubscribe();
868
- }
869
- }, [subscription]);
870
- const renderIsScheduled = useRef(false);
871
- const actualChildPropsSelector = useCallback(() => {
872
- return childPropsSelector(contextValue.getState(), wrapperProps);
873
- }, [contextValue, wrapperProps, childPropsSelector]);
874
- // Our re-subscribe logic only runs when the store/subscription setup changes
875
- const subscribe = useCallback((reactUpdate) => {
876
- if (!subscription) {
877
- return noop;
878
- }
879
- subscription.setOnStateChange(() => {
880
- if (!renderIsScheduled.current) {
881
- renderIsScheduled.current = true;
882
- schedule(() => {
883
- reactUpdate();
884
- renderIsScheduled.current = false;
885
- });
886
- }
887
- });
888
- return () => {
889
- return subscription.tryUnsubscribe();
890
- };
891
- }, [subscription]);
892
- const actualChildProps = useSyncExternalStore(subscribe, actualChildPropsSelector, serverState ? () => childPropsSelector(serverState, wrapperProps) : actualChildPropsSelector);
893
- // Now that all that's done, we can finally try to actually render the child component.
894
- // We memoize the elements for the rendered child component as an optimization.
895
- const renderedWrappedComponent = useMemo(
896
- // eslint-disable-next-line react/jsx-props-no-spreading
897
- () => jsx(WrappedComponent, { ...actualChildProps, ref: forwardedRef }), [forwardedRef, actualChildProps]);
898
- return renderedWrappedComponent;
899
- };
900
- // If we're in "pure" mode, ensure our wrapper component only re-renders when incoming props have changed.
901
- const Connect = pure ? React.memo(ConnectFunction) : ConnectFunction;
902
- Connect.WrappedComponent = WrappedComponent;
903
- Connect.displayName = displayName;
904
- if (forwardRef) {
905
- const forwarded = React.forwardRef(function forwardConnectRef(props, ref) {
906
- // eslint-disable-next-line react/jsx-props-no-spreading
907
- return jsx(Connect, { ...props, forwardedRef: ref });
908
- });
909
- forwarded.displayName = displayName;
910
- forwarded.WrappedComponent = WrappedComponent;
911
- return hoistStatics(forwarded, WrappedComponent);
912
- }
913
- return hoistStatics(Connect, WrappedComponent);
914
- };
915
- }
916
-
917
- const getLogger = () => console;
918
-
919
- function verifyPlainObject(value, displayName, methodName) {
920
- if (!isPlainObject(value)) {
921
- getLogger().debug(`${methodName}() in ${displayName} must return a plain object. Instead received ${value}.`);
922
- }
923
- }
924
-
925
- function verifyFunction(value, displayName, methodName) {
926
- if (!isFunction(value)) {
927
- getLogger().debug(`${methodName}() in ${displayName} must be a function. Instead received ${JSON.stringify(value)}.`);
928
- }
929
- }
930
-
931
- function wrapMapToPropsConstant(getConstant) {
932
- return function initConstantSelector(context, options) {
933
- const constantSelector = always(getConstant(context, options));
934
- constantSelector.dependsOnOwnProps = false;
935
- return constantSelector;
936
- };
937
- }
938
- // dependsOnOwnProps is used by createMapToPropsProxy to determine whether to pass props as args
939
- // to the mapToProps function being wrapped. It is also used by makePurePropsSelector to determine
940
- // whether mapToProps needs to be invoked when props have changed.
941
- //
942
- // A length of one signals that mapToProps does not depend on props from the parent component.
943
- // A length of zero is assumed to mean mapToProps is getting args via arguments or ...args and
944
- // therefore not reporting its length accurately..
945
- function getDependsOnOwnProps(mapToProps) {
946
- return mapToProps.dependsOnOwnProps !== null && mapToProps.dependsOnOwnProps !== undefined
947
- ? Boolean(mapToProps.dependsOnOwnProps)
948
- : mapToProps.length !== 1;
949
- }
950
- // Used by whenMapStateToPropsIsFunction and whenMapDispatchToPropsIsFunction,
951
- // this function wraps mapToProps in a proxy function which does several things:
952
- //
953
- // * Detects whether the mapToProps function being called depends on props, which
954
- // is used by selectorFactory to decide if it should reinvoke on props changes.
955
- //
956
- // * On first call, handles mapToProps if returns another function, and treats that
957
- // new function as the true mapToProps for subsequent calls.
958
- //
959
- // * On first call, verifies the first result is a plain object, in order to warn
960
- // the developer that their mapToProps function is not returning a valid result.
961
- //
962
- function wrapMapToPropsFunc(mapToProps, methodName) {
963
- return function initProxySelector(context, { displayName }) {
964
- const proxy = (stateOrContext, ownProps) => proxy.dependsOnOwnProps
965
- ? proxy.mapToProps(stateOrContext, ownProps)
966
- : proxy.mapToProps(stateOrContext, undefined);
967
- // allow detectFactoryAndVerify to get ownProps
968
- proxy.dependsOnOwnProps = true;
969
- proxy.mapToProps = function detectFactoryAndVerify(stateOrContext, ownProps) {
970
- proxy.mapToProps = mapToProps;
971
- proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps);
972
- let props = proxy(stateOrContext, ownProps);
973
- if (typeof props === 'function') {
974
- proxy.mapToProps = props;
975
- proxy.dependsOnOwnProps = getDependsOnOwnProps(props);
976
- props = proxy(stateOrContext, ownProps);
977
- }
978
- if (process.env.NODE_ENV !== 'production') {
979
- verifyPlainObject(props, displayName, methodName);
980
- }
981
- return props;
982
- };
983
- return proxy;
984
- };
985
- }
986
- function wrapMapToPropsObject(actionsObject) {
987
- function getConstant({ executeAction }, { displayName }) {
988
- return mapObject((action, actionName) => {
989
- if (process.env.NODE_ENV !== 'production') {
990
- verifyFunction(action, displayName, actionName);
991
- }
992
- return (params) => executeAction(action, params);
993
- }, actionsObject);
994
- }
995
- return wrapMapToPropsConstant(getConstant);
996
- }
997
-
998
- function whenMapContextToPropsIsFunction(mapContextToProps) {
999
- return typeof mapContextToProps === 'function'
1000
- ? wrapMapToPropsFunc(mapContextToProps, 'mapContextToProps')
1001
- : undefined;
1002
- }
1003
- function whenMapContextToPropsIsMissing(mapContextToProps) {
1004
- return !mapContextToProps ? wrapMapToPropsConstant(always({})) : undefined;
1005
- }
1006
- function whenMapContextToPropsIsObject(mapContextToProps) {
1007
- return typeof mapContextToProps === 'object' && mapContextToProps !== null
1008
- ? wrapMapToPropsObject(mapContextToProps)
1009
- : undefined;
1010
- }
1011
- const mapContextToPropsFactories = [
1012
- whenMapContextToPropsIsObject,
1013
- whenMapContextToPropsIsFunction,
1014
- whenMapContextToPropsIsMissing,
1015
- ];
1016
-
1017
- function whenMapStateToPropsIsFunction(mapStateToProps) {
1018
- return typeof mapStateToProps === 'function'
1019
- ? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
1020
- : undefined;
1021
- }
1022
- function whenMapStateToPropsIsMissing(mapStateToProps) {
1023
- return !mapStateToProps ? wrapMapToPropsConstant(always({})) : undefined;
1024
- }
1025
- const mapStateToPropsFactories = [
1026
- whenMapStateToPropsIsFunction,
1027
- whenMapStateToPropsIsMissing,
1028
- ];
1029
-
1030
- const defaultMergeProps = (stateProps, contextProps, ownProps) => {
1031
- return { ...ownProps, ...stateProps, ...contextProps };
1032
- };
1033
- function wrapMergePropsFunc(mergeProps) {
1034
- return function initMergePropsProxy(context, { displayName, pure, areMergedPropsEqual }) {
1035
- let hasRunOnce = false;
1036
- let mergedProps;
1037
- return function mergePropsProxy(stateProps, contextProps, ownProps) {
1038
- const nextMergedProps = mergeProps(stateProps, contextProps, ownProps);
1039
- if (hasRunOnce) {
1040
- if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps)) {
1041
- mergedProps = nextMergedProps;
1042
- }
1043
- }
1044
- else {
1045
- hasRunOnce = true;
1046
- mergedProps = nextMergedProps;
1047
- if (process.env.NODE_ENV !== 'production') {
1048
- verifyPlainObject(mergedProps, displayName, 'mergeProps');
1049
- }
1050
- }
1051
- return mergedProps;
1052
- };
1053
- };
1054
- }
1055
- function whenMergePropsIsFunction(mergeProps) {
1056
- return typeof mergeProps === 'function' ? wrapMergePropsFunc(mergeProps) : undefined;
1057
- }
1058
- function whenMergePropsIsOmitted(mergeProps) {
1059
- return !mergeProps ? () => defaultMergeProps : undefined;
1060
- }
1061
- const mergePropsFactories = [whenMergePropsIsFunction, whenMergePropsIsOmitted];
1062
-
1063
- const verifyMapToProps = (mapStateToProps, name) => {
1064
- function verify(state, props) {
1065
- const firstStateProps = mapStateToProps(state, props);
1066
- const secondStateProps = mapStateToProps(state, props);
1067
- if (!shallowEqual(firstStateProps, secondStateProps)) {
1068
- getLogger().warn('Component "%s" recreate equal props %s', name, Object.keys(firstStateProps)
1069
- .filter((key) => firstStateProps[key] !== secondStateProps[key])
1070
- .map((key) => `"${key}"`)
1071
- .join(', '));
1072
- }
1073
- verify.dependsOnOwnProps = mapStateToProps.dependsOnOwnProps;
1074
- return secondStateProps;
1075
- }
1076
- return verify;
1077
- };
1078
-
1079
- function impureFinalPropsSelectorFactory(mapStateToProps, mapContextToProps, mergeProps, context) {
1080
- return function impureFinalPropsSelector(state, ownProps) {
1081
- return mergeProps(mapStateToProps(state, ownProps), mapContextToProps(context, ownProps), ownProps);
1082
- };
1083
- }
1084
- // eslint-disable-next-line max-params
1085
- function pureFinalPropsSelectorFactory(mapStateToProps, mapContextToProps, mergeProps, context, { areStatesEqual, areOwnPropsEqual, areStatePropsEqual, WrappedComponent: { defaultProps } }) {
1086
- let hasRunAtLeastOnce = false;
1087
- let state;
1088
- let ownProps;
1089
- let ownPropsWithDefault;
1090
- let stateProps;
1091
- let contextProps;
1092
- let mergedProps;
1093
- function handleFirstCall(firstState, firstOwnProps) {
1094
- state = firstState;
1095
- ownProps = firstOwnProps;
1096
- ownPropsWithDefault = { ...defaultProps, ...firstOwnProps }; // TODO проверить зачем мержить пропсы с defaultProps, взято из старого connect, иначе падают некоторые тесты
1097
- stateProps = mapStateToProps(state, ownPropsWithDefault);
1098
- contextProps = mapContextToProps(context, ownPropsWithDefault);
1099
- mergedProps = mergeProps(stateProps, contextProps, ownProps);
1100
- hasRunAtLeastOnce = true;
1101
- return mergedProps;
1102
- }
1103
- function handleNewPropsAndNewState() {
1104
- stateProps = mapStateToProps(state, ownPropsWithDefault);
1105
- if (mapContextToProps.dependsOnOwnProps) {
1106
- contextProps = mapContextToProps(context, ownPropsWithDefault);
1107
- }
1108
- mergedProps = mergeProps(stateProps, contextProps, ownProps);
1109
- return mergedProps;
1110
- }
1111
- function handleNewProps() {
1112
- if (mapStateToProps.dependsOnOwnProps) {
1113
- stateProps = mapStateToProps(state, ownPropsWithDefault);
1114
- }
1115
- if (mapContextToProps.dependsOnOwnProps) {
1116
- contextProps = mapContextToProps(context, ownPropsWithDefault);
1117
- }
1118
- mergedProps = mergeProps(stateProps, contextProps, ownProps);
1119
- return mergedProps;
1120
- }
1121
- function handleNewState() {
1122
- const nextStateProps = mapStateToProps(state, ownPropsWithDefault);
1123
- const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps);
1124
- stateProps = nextStateProps;
1125
- if (statePropsChanged) {
1126
- mergedProps = mergeProps(stateProps, contextProps, ownProps);
1127
- }
1128
- return mergedProps;
1129
- }
1130
- function handleSubsequentCalls(nextState, nextOwnProps) {
1131
- const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps);
1132
- const stateChanged = !areStatesEqual(nextState, state);
1133
- state = nextState;
1134
- ownProps = nextOwnProps;
1135
- ownPropsWithDefault = { ...defaultProps, ...nextOwnProps };
1136
- if (propsChanged && stateChanged) {
1137
- return handleNewPropsAndNewState();
1138
- }
1139
- if (propsChanged) {
1140
- return handleNewProps();
1141
- }
1142
- if (stateChanged) {
1143
- return handleNewState();
1144
- }
1145
- return mergedProps;
1146
- }
1147
- return function pureFinalPropsSelector(nextState, nextOwnProps) {
1148
- return hasRunAtLeastOnce
1149
- ? handleSubsequentCalls(nextState, nextOwnProps)
1150
- : handleFirstCall(nextState, nextOwnProps);
1151
- };
1152
- }
1153
- // TODO: Add more comments
1154
- // If pure is true, the selector returned by selectorFactory will memoize its results,
1155
- // allowing connectAdvanced's shouldComponentUpdate to return false if final
1156
- // props have not changed. If false, the selector will always return a new
1157
- // object and shouldComponentUpdate will always return true.
1158
- function finalPropsSelectorFactory(context, { initMapStateToProps, initMapContextToProps, initMergeProps, ...options }) {
1159
- let mapStateToProps = initMapStateToProps(context, options);
1160
- const mapContextToProps = initMapContextToProps(context, options);
1161
- const mergeProps = initMergeProps(context, options);
1162
- if (process.env.NODE_ENV !== 'production') {
1163
- mapStateToProps = verifyMapToProps(mapStateToProps, options.WrappedComponent.name);
1164
- }
1165
- const selectorFactory = options.pure
1166
- ? pureFinalPropsSelectorFactory
1167
- : impureFinalPropsSelectorFactory;
1168
- return selectorFactory(mapStateToProps, mapContextToProps, mergeProps, context, options);
1169
- }
1170
-
1171
- const Provider = ({ context, children, serverState, }) => {
1172
- return (jsx(ConnectContext.Provider, { value: context, children: jsx(ServerStateContext.Provider, { value: serverState, children: children }) }));
1173
- };
1174
-
1175
- /*
1176
- connect is a facade over connectAdvanced. It turns its args into a compatible
1177
- selectorFactory, which has the signature:
1178
- (dispatch, options) => (nextState, nextOwnProps) => nextFinalProps
1179
-
1180
- connect passes its args to connectAdvanced as options, which will in turn pass them to
1181
- selectorFactory each time a Connect component instance is instantiated or hot reloaded.
1182
- selectorFactory returns a final props selector from its mapStateToProps,
1183
- mapStateToPropsFactories, mapContextToProps, mapContextToPropsFactories, mergeProps,
1184
- mergePropsFactories, and pure args.
1185
- The resulting final props selector is called by the Connect component instance whenever
1186
- it receives new props or store state.
1187
- */
1188
- function match(arg, factories, name) {
1189
- for (let i = factories.length - 1; i >= 0; i--) {
1190
- const result = factories[i](arg);
1191
- if (result) {
1192
- return result;
1193
- }
1194
- }
1195
- return (context, options) => {
1196
- throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`);
1197
- };
1198
- }
1199
- // createConnect with default args builds the 'official' connect behavior. Calling it with
1200
- // different options opens up some testing and extensibility scenarios
1201
- /**
1202
- * @deprecated
1203
- */
1204
- function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories: mapStateToPropsFactories$1 = mapStateToPropsFactories, mapContextToPropsFactories: mapContextToPropsFactories$1 = mapContextToPropsFactories, mergePropsFactories: mergePropsFactories$1 = mergePropsFactories, selectorFactory = finalPropsSelectorFactory, schedule = scheduling(), } = {}) {
1205
- return (stores, mapStateToProps, mapContextToProps, mergeProps, { pure = true, areStatesEqual = strictEqual, areOwnPropsEqual = shallowEqual, areStatePropsEqual = shallowEqual, areMergedPropsEqual = shallowEqual, ...extraOptions } = {}
1206
- // eslint-disable-next-line max-params
1207
- ) => {
1208
- // @ts-ignore
1209
- const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories$1, 'mapStateToProps');
1210
- // @ts-ignore
1211
- const initMapContextToProps = match(mapContextToProps,
1212
- // @ts-ignore
1213
- mapContextToPropsFactories$1, 'mapContextToProps');
1214
- // @ts-ignore
1215
- const initMergeProps = match(mergeProps, mergePropsFactories$1, 'mergeProps');
1216
- return connectHOC(selectorFactory, {
1217
- // @ts-ignore
1218
- stores,
1219
- // passed through to selectorFactory 2
1220
- // @ts-ignore
1221
- initMapStateToProps,
1222
- initMapContextToProps,
1223
- initMergeProps,
1224
- pure,
1225
- areStatesEqual,
1226
- areOwnPropsEqual,
1227
- areStatePropsEqual,
1228
- areMergedPropsEqual,
1229
- schedule,
1230
- // used in error messages
1231
- methodName: 'connect',
1232
- // used to compute Connect's displayName from the wrapped component's displayName.
1233
- getDisplayName: (name) => `Connect(${name})`,
1234
- // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes
1235
- shouldHandleStateChanges: stores && stores.length > 0,
1236
- // any extra options args can override defaults of connect or connectAdvanced
1237
- ...extraOptions,
1238
- });
1239
- };
1240
- }
1241
- /**
1242
- * @deprecated
1243
- */
1244
- const connect = /* @__PURE__ */ createConnect();
1245
- const { Consumer } = ConnectContext;
1246
-
1247
- export { BaseStore, ChildDispatcherContext, Consumer, Dispatcher, DispatcherContext, Provider, Subscription, connect, convertAction, createConnect, createDispatcher, createEvent, createReducer, index as devTools, useActions, useConsumerContext, useSelector, useStore, useStoreSelector };