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