@tramvai/state 1.8.5 → 1.9.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/README.en.md ADDED
@@ -0,0 +1,53 @@
1
+ # State
2
+
3
+ **State** is a library built into `tramvai` for managing application state.
4
+
5
+ ## Peculiarities
6
+
7
+ - Redux-like state manager
8
+ - Built-in library similar to [redux-act](https://github.com/pauldijou/redux-act) to reduce boilerplate code
9
+ - Contains bindings to `react` components such as `connect` and `useSelector`
10
+ - Dynamic initialization of reducers. You can register a reducer at any time or generate a new one.
11
+ - Point subscriptions to changes in the states of reducers. When data changes, only the affected `connect` and `useSelector` are recalculated, not everything.
12
+ - Support for SSR mode.
13
+
14
+ ## Basic concepts
15
+
16
+ - Store - A class that contains the state of all reducers, change subscriptions and is created for each client
17
+ - Reducers - entities in which we describe how data will be stored and transformed
18
+ - Events - events with which you can change the states of reducers
19
+ - Actions - functions that allow you to perform side effects and update data in the store. Similar to `redux-thunk`
20
+
21
+ ## Recommendations
22
+
23
+ - You cannot mutate data in reducers. Otherwise, due to various optimizations, subscribers will not be notified about the changes.
24
+ - Initialize reducers as early as possible and before using it. Otherwise, when calling `dispatch(userLoadInformation())`, the reducer will not yet track events and will not receive data.
25
+ - Do not store static data in stores. Since this data will be transferred from the server to the client, the data will be duplicated. Better to put in constants.
26
+ - Break into small reducers. Otherwise, we have a huge reducer that contains a large amount of information and any changes will cause recalculations for a large number of components.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm i --save @tramvai/state
32
+ ```
33
+
34
+ ## Basic example
35
+
36
+ ```tsx
37
+ import { createReducer, createEvent } from '@tramvai/state';
38
+
39
+ export const userLoadInformation = createEvent('user load information');
40
+ export const userAddInformation = createEvent('user add information');
41
+
42
+ const userReducer = createReducer('user', {
43
+ info: {},
44
+ })
45
+ .on(userLoadInformation, (state, info) => ({ info }))
46
+ .on(userAddInformation, (state, { name, info }) => ({
47
+ ...state,
48
+ state: {
49
+ ...state.info,
50
+ [name]: info,
51
+ },
52
+ }));
53
+ ```
@@ -0,0 +1,135 @@
1
+ # State hooks
2
+
3
+ ## useActions
4
+
5
+ Allows to execute tram [actions](concepts/action.md) in React components
6
+
7
+ ### Interface
8
+
9
+ - `actions` - one or an array of tram actions
10
+
11
+ > If you pass an array to `useActions`, for typing you need to specify `as const` - `useActions([] as const)`
12
+
13
+ ### Usage
14
+
15
+ ```tsx
16
+ import { useActions } from '@tramvai/state';
17
+ import { loadUserAction, getInformationAction, setInformationAction } from './actions';
18
+
19
+ export const Component = () => {
20
+ // if you pass one action, the payload type for loadUser is automatically deduced
21
+ const loadUser = useActions(loadUserAction);
22
+
23
+ // if you pass a list of actions, `as const` is required for correct type inference
24
+ const [getInformation, setInformation] = useActions([
25
+ getInformationAction,
26
+ setInformationAction,
27
+ ] as const);
28
+
29
+ return (
30
+ <div>
31
+ <div onClick={loadUser}>load user</div>
32
+ <div onClick={getInformation}>get information</div>
33
+ <div onClick={() => setInformation({ user: 1 })}>set information</div>
34
+ </div>
35
+ );
36
+ };
37
+ ```
38
+
39
+ ## useSelector ()
40
+
41
+ Receiving data from the store in components
42
+
43
+ ### Interface
44
+
45
+ - `stores: []` - a list of tokens that the selector will subscribe to. Will affect which store changes will trigger an update in the component
46
+ - `selector: (state) => any` - the selector itself, this is a function that will be called upon initialization and any changes to the stores passed to `stores`. The function should return data that can be used in the component
47
+ - `equalityFn?: (cur, prev) => boolean` - optional function to change the way of comparing past and new values ​​of a selector
48
+
49
+ ### Usage
50
+
51
+ To get data from a store, you can use a store name, a reference to a store, or an object with an optional store:
52
+
53
+ - `'storeName'`
54
+ - `storeObject`
55
+ - `{ store: storeObject, optional: true }`
56
+ - `{ store: 'storeName', optional: true }`
57
+
58
+ You can pass an array of keys, then for correct type inference it is better to use `as const`:
59
+
60
+ - `useSelector(['fooStoreName', barStoreObject] as const, ({ foo, bar }) => null)`;
61
+
62
+ ```tsx
63
+ import { useSelector } from '@tramvai/state';
64
+
65
+ export const Component = () => {
66
+ const isBrowser = useSelector('media', (state) => state.media.isBrowser);
67
+
68
+ return <div>{isBrowser ? <span>Browser</span> : <span>Desktop</span>}</div>;
69
+ };
70
+ ```
71
+
72
+ ### Optimizations
73
+
74
+ In order to reduce the number of component redrawings, after each call to `selector`, the return values ​​are checked against those that were before. If the returned selector data has not changed, then the component will not be redrawn.
75
+
76
+ For this reason, it is better to get small chunks of information in selectors. Then there is less chance that the component will be updated. For example: we need the user's `roles`, we write a selector that requests all user data `(state) => state.user` and now any changes to the `user` reducer will update the component. It is better if we receive only the necessary data `(state) => state.user.roles`, in which case the component will be redrawn only when the user's `roles` change
77
+
78
+ ## useStoreSelector
79
+
80
+ A simplified version of the useSelector hook into which only one store can be passed, created via createReducer. It was made to improve the inference of selector types, since useSelector itself cannot do this due to the use of strings, tokens and BaseStore heirs inside string names
81
+
82
+ ### Interface
83
+
84
+ - `store: Reducer` - Store created through createReducer
85
+ - `selector: (state) => any` - the selector itself, this is a function that will be called upon initialization and any changes to the store passed to `stores`. The function should return data that can be used in the component
86
+
87
+ ### Usage
88
+
89
+ ```tsx
90
+ import { useStoreSelector } from '@tramvai/state';
91
+ import { createReducer } from '@tramvai/state';
92
+
93
+ const myStore = createReducer('myStore', { id: '123' });
94
+
95
+ export const Component = () => {
96
+ const id = useStoreSelector((myStore, (state) => state.id)); // The id type will be correctly inferred as "string"
97
+
98
+ return <div>{id}</div>;
99
+ };
100
+ ```
101
+
102
+ ### Optimizations
103
+
104
+ The hook is a wrapper over useSelector, so the optimizations are the same. The selector function itself is memoized inside
105
+
106
+ ## useStore
107
+
108
+ Hook to get the state of a specific reducer.
109
+
110
+ Peculiarities:
111
+
112
+ - automatically displays the type of state
113
+ - re-renders the component only when the reducer is updated
114
+ - allows you to create reducers "on the fly"
115
+
116
+ ### Interface
117
+
118
+ - `store: Reducer` - Store created by createReducer
119
+
120
+ ### Usage
121
+
122
+ Basic example:
123
+
124
+ ```tsx
125
+ import { useStore } from '@tramvai/state';
126
+ import { createReducer } from '@tramvai/state';
127
+
128
+ const userReducer = createReducer('user', { id: '123' });
129
+
130
+ export const Component = () => {
131
+ const { id } = useStore(userReducer);
132
+
133
+ return <div>{id}</div>;
134
+ };
135
+ ```
@@ -0,0 +1,63 @@
1
+ # createEvent
2
+
3
+ The `createEvent` method creates an event that can be subscribed to in state management
4
+
5
+ ## Method Description
6
+
7
+ `createEvent(eventName: string, payloadCreator?: PayloadTransformer): EventCreator`
8
+
9
+ - `eventName` - Unique identifier of the event
10
+ - `payloadCreator` - an optional function that allows you to combine multiple arguments into one, In cases where the event was called with multiple arguments.
11
+
12
+ ## Examples
13
+
14
+ #### Creating an event without parameters
15
+
16
+ ```tsx
17
+ import { createEvent } from '@tramvai/state';
18
+
19
+ const userLoadingInformation = createEvent('user loading information');
20
+
21
+ userLoadingInformation();
22
+ ```
23
+
24
+ #### Creating an event with parameters
25
+
26
+ ```tsx
27
+ import { createEvent } from '@tramvai/state';
28
+
29
+ const userInformation = createEvent<{ age: number; name: string }>('user information');
30
+
31
+ userInformation({ age: 42, name: 'Tom' });
32
+ ```
33
+
34
+ #### Create event with payload conversion
35
+
36
+ ```tsx
37
+ import { createEvent } from '@tramvai/state';
38
+
39
+ const itemPrice = createEvent('user information', (info: string, price: number) => ({
40
+ [info]: price,
41
+ }));
42
+
43
+ itemPrice('car', 3000);
44
+ ```
45
+
46
+ #### Using Events in Actions
47
+
48
+ We create an action in which, after loading the information, we create an event and throw it into context.dispatch
49
+
50
+ ```javascript
51
+ import { createAction } from '@tramvai/core';
52
+ import { createEvent } from '@tramvai/state';
53
+
54
+ const userInformation = createEvent < { age: number, name: string } > 'user information';
55
+
56
+ const action = createAction({
57
+ name: 'userLoadInformation',
58
+ fn: async (context) => {
59
+ const result = await tinkoffRequest({ method: 'information' });
60
+ context.dispatch(userInformation(result));
61
+ },
62
+ });
63
+ ```
@@ -0,0 +1,101 @@
1
+ # createReducer
2
+
3
+ The `createReducer` method creates reducer functions that describe the state during initialization and the reaction to state changes.
4
+
5
+ The working principle and api is built based on: https://redux.js.org/basics/reducers and the use interface from https://github.com/pauldijou/redux-act#createreducerhandlers-defaultstate
6
+
7
+ ### Method Description
8
+
9
+ `createReducer(name, initialState)`
10
+
11
+ - `name` - unique name of the reducer. Should not overlap with other reducers
12
+ - `initialState` - default reducer state
13
+
14
+ ### Typing
15
+
16
+ By default, the reducer state type and name are displayed automatically:
17
+
18
+ ```tsx
19
+ import { createReducer } from '@tramvai/state';
20
+
21
+ const userReducer = createReducer('user', { name: 'anonymus' });
22
+ ```
23
+
24
+ Why do we need typing for the name of the reducer at all?
25
+ Then this reducer will be more convenient to use together with `useSelector`.
26
+
27
+ If you pass the state type manually, it is desirable to specify the name as the second argument of the generic:
28
+
29
+ ```tsx
30
+ import { createReducer } from '@tramvai/state';
31
+
32
+ type UserState = { name: string };
33
+
34
+ const userReducer = createReducer<UserState, 'user'>('user', { name: 'anonymus' });
35
+ ```
36
+
37
+ But, you can simply set the desired type for `initialState`:
38
+
39
+ ```tsx
40
+ import { createReducer } from '@tramvai/state';
41
+
42
+ type UserState = { name?: string };
43
+
44
+ const userReducer = createReducer('user', {} as UserState);
45
+ ```
46
+
47
+ ### Subscription to events
48
+
49
+ `.on(evnet, reducer)` When creating a reducer, the .on method becomes available, which allows you to subscribe to events and return a new state
50
+
51
+ - `event` - an event or a string to which the reducer will be subscribed
52
+ - `reducer(state, payload)` - a pure function that takes the current `state`, `payload` from the event and must return the new state of the reducer
53
+
54
+ **_An example of using the `.on` method_**
55
+
56
+ ```javascript
57
+ import { createReducer, createEvent } from '@tramvai/state';
58
+
59
+ export const userLoadInformation = createEvent < { status: string } > 'user load information';
60
+ export const userAddInformation = createEvent < { name: string, info: {} } > 'user add information';
61
+
62
+ const userReducer = createReducer('user', {
63
+ info: {},
64
+ })
65
+ .on(userLoadInformation, (state, info) => ({ info }))
66
+ .on(userAddInformation, (state, { name, info }) => ({
67
+ ...state,
68
+ state: {
69
+ ...state.info,
70
+ [name]: info,
71
+ },
72
+ }));
73
+ ```
74
+
75
+ ### Automatic creation of events
76
+
77
+ `.createEvents(model)` method that removes the need to create and explicitly bind events
78
+
79
+ - `model` - an object in which the key is the event identifier, which will then be passed to `createEvent`, and the value is the reducer function, which will get into the `.on()` method and will be called when the events are triggered
80
+
81
+ **_An example of using the `.createEvents` method_**
82
+
83
+ ```tsx
84
+ import { createReducer } from '@tramvai/state';
85
+
86
+ const userReducer = createReducer('user', {
87
+ info: {},
88
+ });
89
+ export const { userLoadInformation, userAddInformation } = userReducer.createEvents({
90
+ userLoadInformation: (state, info: { status: string }) => ({ info }),
91
+ userAddInformation: (state, { name, info }: { name: string; info: {} }) => ({
92
+ ...state,
93
+ state: {
94
+ ...state.info,
95
+ [name]: info,
96
+ },
97
+ }),
98
+ });
99
+ ```
100
+
101
+ It is imperative to describe the types of the `payload` argument in reducers, otherwise type inference for events will not work.
@@ -0,0 +1,24 @@
1
+ # Redux devtools
2
+
3
+ To enable devtools, you need to run:
4
+
5
+ - Install browser extension: [Chrome extension](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) or [FireFox extension](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/)
6
+ - Open the page on `tramvai` and open the extension by clicking on the Redux devtools icon
7
+
8
+ ![Redux devtools](https://cloud.githubusercontent.com/assets/7957859/18002950/aacb82fc-6b93-11e6-9ae9-609862c18302.png)
9
+
10
+ ### Possible problems
11
+
12
+ 1. For a better user experience, you need to use a separate redux dev tools extension window, not a tab in chrome developer tools, because otherwise the action history is not saved, see [issue](https://github.com/zalmoxisus/redux-devtools-extension/issues/505).
13
+
14
+ ### Performance
15
+
16
+ Since the entire state of the application with all the actions is quite large, there are noticeable brakes when working with devtools when using jumps over states/events and when a large number of actions are triggered simultaneously. That's why:
17
+
18
+ 1. Use customization techniques to set pickState to reduce the size of data in devtools.
19
+ 1. Increase the value of the latency parameter (passed to connectViaExtension.connect), which essentially debounces sending actions to the extension, see [docs](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#latency)
20
+
21
+ ### Additional links
22
+
23
+ - [Devtools repository](https://github.com/zalmoxisus/redux-devtools-extension)
24
+ - [Getting Started with Redux DevTools Extension ](https://egghead.io/lessons/javascript-getting-started-with-redux-dev-tools)
package/lib/index.js CHANGED
@@ -169,7 +169,7 @@ class DispatcherContext extends SimpleEmitter {
169
169
  subscribe: this.subscribe.bind(this),
170
170
  dispatch: (...args) => dispatch(...args),
171
171
  };
172
- dispatch = compose__default['default'](...middlewares.map((middleware) => middleware(api)))(this.applyDispatch);
172
+ dispatch = compose__default["default"](...middlewares.map((middleware) => middleware(api)))(this.applyDispatch);
173
173
  return dispatch;
174
174
  }
175
175
  // eslint-disable-next-line max-statements
@@ -468,9 +468,9 @@ function createDispatcher(options) {
468
468
  return new Dispatcher(options);
469
469
  }
470
470
 
471
- function createEvent(eventName, payloadCreator = identity__default['default']) {
471
+ function createEvent(eventName, payloadCreator = identity__default["default"]) {
472
472
  if (process.env.NODE_ENV !== 'production') {
473
- if (!isString__default['default'](eventName) || !eventName.length) {
473
+ if (!isString__default["default"](eventName) || !eventName.length) {
474
474
  throw new Error(`eventName should be not empty string, got '${eventName}'`);
475
475
  }
476
476
  }
@@ -555,7 +555,7 @@ class BaseStore extends SimpleEmitter {
555
555
  return this.state;
556
556
  }
557
557
  dehydrate() {
558
- return pick__default['default'](Object.keys(this.hydrateKeys), this.state);
558
+ return pick__default["default"](Object.keys(this.hydrateKeys), this.state);
559
559
  }
560
560
  rehydrate(state) {
561
561
  this.setStateSilently(state);
@@ -637,7 +637,7 @@ function useActions(actions) {
637
637
  const context = useConsumerContext();
638
638
  const actionsRef = reactHooks.useShallowEqual(actions);
639
639
  return React.useMemo(() => {
640
- if (isArray__default['default'](actionsRef)) {
640
+ if (isArray__default["default"](actionsRef)) {
641
641
  return actionsRef.map((action) => context.executeAction.bind(context, action));
642
642
  }
643
643
  return context.executeAction.bind(context, actionsRef);
@@ -659,7 +659,7 @@ function useStore(reducer) {
659
659
  const stateRef = React.useRef();
660
660
  const reducerRef = React.useRef(reducer);
661
661
  const addedReducerRef = React.useRef(null);
662
- const unsubscribeRef = React.useRef(noop__default['default']);
662
+ const unsubscribeRef = React.useRef(noop__default["default"]);
663
663
  const [, forceRender] = React.useReducer((s) => s + 1, 0);
664
664
  React.useMemo(() => {
665
665
  // отписываемся от обновлений текущего редьюсера
@@ -713,13 +713,13 @@ function scheduling() {
713
713
  }
714
714
 
715
715
  const schedule = scheduling();
716
- function useSelector(storesOrStore, selector, equalityFn = shallowEqual__default['default']) {
717
- invariant__default['default'](selector, `You must pass a selector to useSelectors`);
716
+ function useSelector(storesOrStore, selector, equalityFn = shallowEqual__default["default"]) {
717
+ invariant__default["default"](selector, `You must pass a selector to useSelectors`);
718
718
  const context = useConsumerContext();
719
719
  const [, forceRender] = React.useReducer((s) => s + 1, 0);
720
720
  const renderIsScheduled = React.useRef(false);
721
721
  const storesRef = reactHooks.useShallowEqual(storesOrStore);
722
- const subscription = React.useMemo(() => new Subscription(toArray__default['default'](storesRef).map(context.getStore)), [storesRef, context]);
722
+ const subscription = React.useMemo(() => new Subscription(toArray__default["default"](storesRef).map(context.getStore)), [storesRef, context]);
723
723
  const latestSubscriptionCallbackError = React.useRef();
724
724
  const latestSelector = React.useRef(selector);
725
725
  const latestSelectedState = React.useRef();
@@ -845,7 +845,7 @@ pure = true,
845
845
  ...connectOptions } = {}) {
846
846
  return function wrapWithConnect(WrappedComponent) {
847
847
  if (process.env.NODE_ENV !== 'production') {
848
- invariant__default['default'](reactIs.isValidElementType(WrappedComponent), `You must pass a component to the function returned by ` +
848
+ invariant__default["default"](reactIs.isValidElementType(WrappedComponent), `You must pass a component to the function returned by ` +
849
849
  `${methodName}. Instead received ${stringifyComponent(WrappedComponent)}`);
850
850
  }
851
851
  const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
@@ -875,7 +875,7 @@ pure = true,
875
875
  }, [props]);
876
876
  // Retrieve the store and ancestor subscription via context, if available
877
877
  const contextValue = useConsumerContext();
878
- invariant__default['default'](Boolean(contextValue), `Could not find context in ` +
878
+ invariant__default["default"](Boolean(contextValue), `Could not find context in ` +
879
879
  `"${displayName}". Either wrap the root component in a <Provider>, ` +
880
880
  `or pass a custom React context provider to <Provider> and the corresponding ` +
881
881
  `React context consumer to ${displayName} in connect options.`);
@@ -1011,43 +1011,43 @@ pure = true,
1011
1011
  // We memoize the elements for the rendered child component as an optimization.
1012
1012
  const renderedWrappedComponent = React.useMemo(
1013
1013
  // eslint-disable-next-line react/jsx-props-no-spreading
1014
- () => React__default['default'].createElement(WrappedComponent, Object.assign({}, actualChildProps, { ref: forwardedRef })), [forwardedRef, actualChildProps]);
1014
+ () => React__default["default"].createElement(WrappedComponent, Object.assign({}, actualChildProps, { ref: forwardedRef })), [forwardedRef, actualChildProps]);
1015
1015
  return renderedWrappedComponent;
1016
1016
  };
1017
1017
  // If we're in "pure" mode, ensure our wrapper component only re-renders when incoming props have changed.
1018
- const Connect = pure ? React__default['default'].memo(ConnectFunction) : ConnectFunction;
1018
+ const Connect = pure ? React__default["default"].memo(ConnectFunction) : ConnectFunction;
1019
1019
  Connect.WrappedComponent = WrappedComponent;
1020
1020
  Connect.displayName = displayName;
1021
1021
  if (forwardRef) {
1022
- const forwarded = React__default['default'].forwardRef(function forwardConnectRef(props, ref) {
1022
+ const forwarded = React__default["default"].forwardRef(function forwardConnectRef(props, ref) {
1023
1023
  // eslint-disable-next-line react/jsx-props-no-spreading
1024
- return React__default['default'].createElement(Connect, Object.assign({}, props, { forwardedRef: ref }));
1024
+ return React__default["default"].createElement(Connect, Object.assign({}, props, { forwardedRef: ref }));
1025
1025
  });
1026
1026
  forwarded.displayName = displayName;
1027
1027
  forwarded.WrappedComponent = WrappedComponent;
1028
- return hoistStatics__default['default'](forwarded, WrappedComponent);
1028
+ return hoistStatics__default["default"](forwarded, WrappedComponent);
1029
1029
  }
1030
- return hoistStatics__default['default'](Connect, WrappedComponent);
1030
+ return hoistStatics__default["default"](Connect, WrappedComponent);
1031
1031
  };
1032
1032
  }
1033
1033
 
1034
1034
  const getLogger = () => console;
1035
1035
 
1036
1036
  function verifyPlainObject(value, displayName, methodName) {
1037
- if (!isPlainObject__default['default'](value)) {
1037
+ if (!isPlainObject__default["default"](value)) {
1038
1038
  getLogger().debug(`${methodName}() in ${displayName} must return a plain object. Instead received ${value}.`);
1039
1039
  }
1040
1040
  }
1041
1041
 
1042
1042
  function verifyFunction(value, displayName, methodName) {
1043
- if (!isFunction__default['default'](value)) {
1043
+ if (!isFunction__default["default"](value)) {
1044
1044
  getLogger().debug(`${methodName}() in ${displayName} must be a function. Instead received ${JSON.stringify(value)}.`);
1045
1045
  }
1046
1046
  }
1047
1047
 
1048
1048
  function wrapMapToPropsConstant(getConstant) {
1049
1049
  return function initConstantSelector(context, options) {
1050
- const constantSelector = always__default['default'](getConstant(context, options));
1050
+ const constantSelector = always__default["default"](getConstant(context, options));
1051
1051
  constantSelector.dependsOnOwnProps = false;
1052
1052
  return constantSelector;
1053
1053
  };
@@ -1102,7 +1102,7 @@ function wrapMapToPropsFunc(mapToProps, methodName) {
1102
1102
  }
1103
1103
  function wrapMapToPropsObject(actionsObject) {
1104
1104
  function getConstant({ executeAction }, { displayName }) {
1105
- return mapObject__default['default']((action, actionName) => {
1105
+ return mapObject__default["default"]((action, actionName) => {
1106
1106
  if (process.env.NODE_ENV !== 'production') {
1107
1107
  verifyFunction(action, displayName, actionName);
1108
1108
  }
@@ -1118,7 +1118,7 @@ function whenMapContextToPropsIsFunction(mapContextToProps) {
1118
1118
  : undefined;
1119
1119
  }
1120
1120
  function whenMapContextToPropsIsMissing(mapContextToProps) {
1121
- return !mapContextToProps ? wrapMapToPropsConstant(always__default['default']({})) : undefined;
1121
+ return !mapContextToProps ? wrapMapToPropsConstant(always__default["default"]({})) : undefined;
1122
1122
  }
1123
1123
  function whenMapContextToPropsIsObject(mapContextToProps) {
1124
1124
  return typeof mapContextToProps === 'object' && mapContextToProps !== null
@@ -1137,7 +1137,7 @@ function whenMapStateToPropsIsFunction(mapStateToProps) {
1137
1137
  : undefined;
1138
1138
  }
1139
1139
  function whenMapStateToPropsIsMissing(mapStateToProps) {
1140
- return !mapStateToProps ? wrapMapToPropsConstant(always__default['default']({})) : undefined;
1140
+ return !mapStateToProps ? wrapMapToPropsConstant(always__default["default"]({})) : undefined;
1141
1141
  }
1142
1142
  const mapStateToPropsFactories = [
1143
1143
  whenMapStateToPropsIsFunction,
@@ -1181,7 +1181,7 @@ const verifyMapToProps = (mapStateToProps, name) => {
1181
1181
  function verify(state, props) {
1182
1182
  const firstStateProps = mapStateToProps(state, props);
1183
1183
  const secondStateProps = mapStateToProps(state, props);
1184
- if (!shallowEqual__default['default'](firstStateProps, secondStateProps)) {
1184
+ if (!shallowEqual__default["default"](firstStateProps, secondStateProps)) {
1185
1185
  getLogger().warn('Component "%s" recreate equal props %s', name, Object.keys(firstStateProps)
1186
1186
  .filter((key) => firstStateProps[key] !== secondStateProps[key])
1187
1187
  .map((key) => `"${key}"`)
@@ -1286,7 +1286,7 @@ function finalPropsSelectorFactory(context, { initMapStateToProps, initMapContex
1286
1286
  }
1287
1287
 
1288
1288
  const Provider = ({ context, children }) => {
1289
- return React__default['default'].createElement(ConnectContext.Provider, { value: context }, children);
1289
+ return React__default["default"].createElement(ConnectContext.Provider, { value: context }, children);
1290
1290
  };
1291
1291
 
1292
1292
  /*
@@ -1316,7 +1316,7 @@ function match(arg, factories, name) {
1316
1316
  // createConnect with default args builds the 'official' connect behavior. Calling it with
1317
1317
  // different options opens up some testing and extensibility scenarios
1318
1318
  function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories: mapStateToPropsFactories$1 = mapStateToPropsFactories, mapContextToPropsFactories: mapContextToPropsFactories$1 = mapContextToPropsFactories, mergePropsFactories: mergePropsFactories$1 = mergePropsFactories, selectorFactory = finalPropsSelectorFactory, schedule = scheduling(), } = {}) {
1319
- return (stores, mapStateToProps, mapContextToProps, mergeProps, { pure = true, areStatesEqual = strictEqual__default['default'], areOwnPropsEqual = shallowEqual__default['default'], areStatePropsEqual = shallowEqual__default['default'], areMergedPropsEqual = shallowEqual__default['default'], ...extraOptions } = {}
1319
+ return (stores, mapStateToProps, mapContextToProps, mergeProps, { pure = true, areStatesEqual = strictEqual__default["default"], areOwnPropsEqual = shallowEqual__default["default"], areStatePropsEqual = shallowEqual__default["default"], areMergedPropsEqual = shallowEqual__default["default"], ...extraOptions } = {}
1320
1320
  // eslint-disable-next-line max-params
1321
1321
  ) => {
1322
1322
  // @ts-ignore
@@ -14,13 +14,13 @@ var noop__default = /*#__PURE__*/_interopDefaultLegacy(noop);
14
14
  var startsWith__default = /*#__PURE__*/_interopDefaultLegacy(startsWith);
15
15
  var isElement__default = /*#__PURE__*/_interopDefaultLegacy(isElement);
16
16
 
17
- const elementReplacer = pick__default['default'](['tagName', 'id', 'className']);
17
+ const elementReplacer = pick__default["default"](['tagName', 'id', 'className']);
18
18
  // eslint-disable-next-line import/no-mutable-exports
19
19
  let devTools = {
20
- init: noop__default['default'],
21
- send: noop__default['default'],
22
- subscribe: noop__default['default'],
23
- error: noop__default['default'],
20
+ init: noop__default["default"],
21
+ send: noop__default["default"],
22
+ subscribe: noop__default["default"],
23
+ error: noop__default["default"],
24
24
  };
25
25
  // eslint-disable-next-line no-underscore-dangle,@typescript-eslint/no-explicit-any
26
26
  if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {
@@ -33,9 +33,9 @@ if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {
33
33
  replacer: (key, value) => {
34
34
  // eslint-disable-next-line default-case
35
35
  switch (true) {
36
- case isElement__default['default'](value):
36
+ case isElement__default["default"](value):
37
37
  return elementReplacer(value);
38
- case startsWith__default['default']('_reactInternal', `${key}`):
38
+ case startsWith__default["default"]('_reactInternal', `${key}`):
39
39
  return '_reactInternal';
40
40
  }
41
41
  return value;
@@ -47,7 +47,7 @@ if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {
47
47
  const DISPATCH = 'DISPATCH';
48
48
 
49
49
  const middleware = ({ pickState } = {}) => (api) => (next) => {
50
- const getState = pickState && pickState.length ? () => pick__default['default'](pickState, api.getState()) : api.getState;
50
+ const getState = pickState && pickState.length ? () => pick__default["default"](pickState, api.getState()) : api.getState;
51
51
  // TODO: типизировать message
52
52
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
53
  devTools.subscribe((message) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/state",
3
- "version": "1.8.5",
3
+ "version": "1.9.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@tinkoff/react-hooks": "0.0.22",
22
22
  "@tinkoff/utils": "^2.1.2",
23
- "@tramvai/types-actions-state-context": "1.8.5",
23
+ "@tramvai/types-actions-state-context": "1.9.0",
24
24
  "@types/hoist-non-react-statics": "^3.3.1",
25
25
  "invariant": "^2.2.4",
26
26
  "react-is": "^17.0.1",