@dr.pogodin/react-global-state 0.6.4 → 0.7.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.md +77 -0
- package/build/{web → module}/GlobalState.js +27 -39
- package/build/module/GlobalState.js.map +1 -0
- package/build/{web → module}/GlobalStateProvider.js +13 -29
- package/build/module/GlobalStateProvider.js.map +1 -0
- package/build/module/index.js +19 -0
- package/build/module/index.js.map +1 -0
- package/build/{web → module}/useAsyncCollection.js +4 -14
- package/build/module/useAsyncCollection.js.map +1 -0
- package/build/{web → module}/useAsyncData.js +30 -45
- package/build/module/useAsyncData.js.map +1 -0
- package/build/{web → module}/useGlobalState.js +17 -31
- package/build/module/useGlobalState.js.map +1 -0
- package/build/{web → module}/utils.js +2 -12
- package/build/module/utils.js.map +1 -0
- package/package.json +27 -23
- package/build/web/GlobalState.js.map +0 -1
- package/build/web/GlobalStateProvider.js.map +0 -1
- package/build/web/index.js +0 -72
- package/build/web/index.js.map +0 -1
- package/build/web/useAsyncCollection.js.map +0 -1
- package/build/web/useAsyncData.js.map +0 -1
- package/build/web/useGlobalState.js.map +0 -1
- package/build/web/utils.js.map +0 -1
- package/index.js +0 -18
- package/node.js +0 -5
- package/web.js +0 -5
package/README.md
CHANGED
|
@@ -257,5 +257,82 @@ of some, or all async data at the server side.
|
|
|
257
257
|
}
|
|
258
258
|
```
|
|
259
259
|
|
|
260
|
+
### Frequently Asked Questions
|
|
261
|
+
|
|
262
|
+
- _Does React Global State library avoid unnecessary component re-renders when values updated in the global state are irrelevant to those components?_
|
|
263
|
+
|
|
264
|
+
Yes, it does avoid unnecessary re-renders of the component tree. A component
|
|
265
|
+
relying on `some.path` in the global state is re-rendered only when the value
|
|
266
|
+
at this path, or its sub-path has changed; _i.e._ it will be re-rendered if
|
|
267
|
+
the value at `some.path` has changed, and it will be re-rendered if the value
|
|
268
|
+
at `some.path.sub.path` has changed.
|
|
269
|
+
|
|
270
|
+
- _How would you describe your use case compared to another React global state library, e.g. [Valtio](https://www.npmjs.com/package/valtio)?_
|
|
271
|
+
|
|
272
|
+
1. React Global State is designed to follow the standard React API as close
|
|
273
|
+
as possible. _E.g._ if some component relies on the local state:
|
|
274
|
+
```jsx
|
|
275
|
+
const [value, setValue] = useState(initialState);
|
|
276
|
+
```
|
|
277
|
+
to move that value to the global state (or _vice versa_) one only needs to
|
|
278
|
+
replace the hook with
|
|
279
|
+
```jsx
|
|
280
|
+
const [value, setValue] = useGlobalState(path, initialState);
|
|
281
|
+
```
|
|
282
|
+
The [useGlobalState()] hook takes care to follow all edge cases of the
|
|
283
|
+
standard [useState()]: `setValue` setter identity is stable (does not
|
|
284
|
+
change on re-renders), functional updates and lazy initial state are
|
|
285
|
+
supported.
|
|
286
|
+
|
|
287
|
+
Other libraries tend to re-invent the wheel, introducing their own APIs,
|
|
288
|
+
which (i) should be learned and understood; (ii) do complicate migration
|
|
289
|
+
of components between the local and global state, should it be needed in
|
|
290
|
+
a course of app development / prototyping.
|
|
291
|
+
|
|
292
|
+
2. When it comes to async data in the global state other libraries tend to
|
|
293
|
+
offer only a very basic supported, often relying on experimental or internal
|
|
294
|
+
React mechanics.
|
|
295
|
+
|
|
296
|
+
React Global State, [useAsyncData()] and [useAsyncCollection()] hooks in
|
|
297
|
+
particular, implements async data fetching and management features: when
|
|
298
|
+
multiple components use these hooks to load async data to the same global
|
|
299
|
+
state path the library takes care to do the actual loading just once, and
|
|
300
|
+
then keep the data without reloading until their age reaches (configurable)
|
|
301
|
+
max age. There is an automated garbage collection of expired, non-used
|
|
302
|
+
async data from the global state; there is server-side rendering (SSR)
|
|
303
|
+
support, with suggested high-level setup taking care that all async data
|
|
304
|
+
loaded using [useAsyncData()] and [useAsyncCollection()] hooks will be
|
|
305
|
+
automatically loaded and used in server-side renders (still allowing to
|
|
306
|
+
opt-out of that for individual hooks, and timeout server-side fetching of
|
|
307
|
+
data that take too long to arrive, in which case the library will fetch
|
|
308
|
+
such data client-side). It does not rely on experimental React APIs to
|
|
309
|
+
achieve its functionality, it only uses current public APIs.
|
|
310
|
+
|
|
311
|
+
For me the support of async data fetching into the global state and their
|
|
312
|
+
further management with out-of-the-box SSR support was the primary
|
|
313
|
+
motivation to create React Global State. There are many other global state
|
|
314
|
+
React libraries, but I was not able to find any that would cover the async
|
|
315
|
+
data handling with that ease I believed was possible. The secondary
|
|
316
|
+
motivation was that existing global state libraries either had
|
|
317
|
+
the shortcoming of unnecessary component re-renders when data irrelevant
|
|
318
|
+
to them where updated in the global state, or introduced their
|
|
319
|
+
own APIs, where following the standard React APIs for local state looks
|
|
320
|
+
to me a way more convenient approach.
|
|
321
|
+
|
|
322
|
+
- _Is React Global State library production ready (considering the current version number 0.y.z)?_
|
|
323
|
+
|
|
324
|
+
Yes. I personally use it in production for all my commercial and personal
|
|
325
|
+
React projects for over an year. I just don't feel like to call it v1 until
|
|
326
|
+
a reasonable adoption by 3rd party developers, and any API improvements that
|
|
327
|
+
may come out of community experience.
|
|
328
|
+
|
|
260
329
|
[Library Reference](https://dr.pogodin.studio/docs/react-global-state/index.html) •
|
|
261
330
|
[Blog Article](https://dr.pogodin.studio/dev-blog/the-global-state-in-react-designed-right)
|
|
331
|
+
|
|
332
|
+
[useAsyncCollection()]: https://dr.pogodin.studio/docs/react-global-state/docs/api/hooks/useasynccollection
|
|
333
|
+
[useAsyncData()]: https://dr.pogodin.studio/docs/react-global-state/docs/api/hooks/useasyncdata
|
|
334
|
+
[useGlobalState()]: https://dr.pogodin.studio/docs/react-global-state/docs/api/hooks/useglobalstate
|
|
335
|
+
[useState()]: https://reactjs.org/docs/hooks-reference.html#usestate
|
|
336
|
+
|
|
337
|
+
[functional updates]: https://reactjs.org/docs/hooks-reference.html#functional-updates
|
|
338
|
+
[lazy initial state]: https://reactjs.org/docs/hooks-reference.html#functional-updates
|
|
@@ -1,28 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
4
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
2
5
|
|
|
3
|
-
var
|
|
6
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
4
7
|
|
|
5
|
-
Object.defineProperty(
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = void 0;
|
|
9
|
-
|
|
10
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
-
|
|
12
|
-
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
13
|
-
|
|
14
|
-
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
15
|
-
|
|
16
|
-
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
17
|
-
|
|
18
|
-
var _lodash = require("lodash");
|
|
19
|
-
|
|
20
|
-
var _utils = require("./utils");
|
|
21
|
-
|
|
22
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
23
|
-
|
|
24
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
8
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
25
9
|
|
|
10
|
+
import { cloneDeep, get as _get, isArray, isObject, isNil, set as _set, toPath } from 'lodash';
|
|
11
|
+
import { isDebugMode } from "./utils";
|
|
26
12
|
var ERR_NO_SSR_WATCH = 'GlobalState must not be watched at server side';
|
|
27
13
|
/**
|
|
28
14
|
* Transform state path into the full path inside GlobalState object.
|
|
@@ -32,7 +18,7 @@ var ERR_NO_SSR_WATCH = 'GlobalState must not be watched at server side';
|
|
|
32
18
|
*/
|
|
33
19
|
|
|
34
20
|
function fullPath(statePath) {
|
|
35
|
-
return
|
|
21
|
+
return isNil(statePath) ? 'state' : "state.".concat(statePath);
|
|
36
22
|
}
|
|
37
23
|
|
|
38
24
|
var GlobalState = /*#__PURE__*/function () {
|
|
@@ -42,10 +28,10 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
42
28
|
* @param {SsrContext} [ssrContext] Server-side rendering context.
|
|
43
29
|
*/
|
|
44
30
|
function GlobalState(initialState, ssrContext) {
|
|
45
|
-
(
|
|
31
|
+
_classCallCheck(this, GlobalState);
|
|
46
32
|
|
|
47
33
|
/* eslint-disable no-param-reassign */
|
|
48
|
-
this.state =
|
|
34
|
+
this.state = cloneDeep(initialState);
|
|
49
35
|
this.nextNotifierId = null;
|
|
50
36
|
this.watchers = [];
|
|
51
37
|
|
|
@@ -56,12 +42,12 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
56
42
|
this.ssrContext = ssrContext;
|
|
57
43
|
}
|
|
58
44
|
|
|
59
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
45
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
60
46
|
/* eslint-disable no-console */
|
|
61
47
|
var msg = 'New ReactGlobalState created';
|
|
62
48
|
if (ssrContext) msg += ' (SSR mode)';
|
|
63
49
|
console.groupCollapsed(msg);
|
|
64
|
-
console.log('Initial state:',
|
|
50
|
+
console.log('Initial state:', cloneDeep(initialState));
|
|
65
51
|
console.groupEnd();
|
|
66
52
|
/* eslint-enable no-console */
|
|
67
53
|
}
|
|
@@ -77,10 +63,10 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
77
63
|
*/
|
|
78
64
|
|
|
79
65
|
|
|
80
|
-
(
|
|
66
|
+
_createClass(GlobalState, [{
|
|
81
67
|
key: "get",
|
|
82
68
|
value: function get(path) {
|
|
83
|
-
return (
|
|
69
|
+
return _get(this, fullPath(path));
|
|
84
70
|
}
|
|
85
71
|
/**
|
|
86
72
|
* Writes the `value` to given global state `path`.
|
|
@@ -97,21 +83,21 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
97
83
|
|
|
98
84
|
var p = fullPath(path);
|
|
99
85
|
|
|
100
|
-
if (value !== (
|
|
101
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
86
|
+
if (value !== _get(this, p)) {
|
|
87
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
102
88
|
/* eslint-disable no-console */
|
|
103
89
|
console.groupCollapsed("ReactGlobalState update. Path: \"".concat(path || '', "\""));
|
|
104
|
-
console.log('New value:',
|
|
90
|
+
console.log('New value:', cloneDeep(value));
|
|
105
91
|
/* eslint-enable no-console */
|
|
106
92
|
}
|
|
107
93
|
|
|
108
94
|
var pos = this;
|
|
109
|
-
var pathSegments =
|
|
95
|
+
var pathSegments = toPath(p);
|
|
110
96
|
|
|
111
97
|
for (var i = 0; i < pathSegments.length - 1; i += 1) {
|
|
112
98
|
var seg = pathSegments[i];
|
|
113
99
|
var next = pos[seg];
|
|
114
|
-
if (
|
|
100
|
+
if (isArray(next)) pos[seg] = _toConsumableArray(next);else if (isObject(next)) pos[seg] = _objectSpread({}, next);else break;
|
|
115
101
|
pos = pos[seg];
|
|
116
102
|
} // TODO: With such naive use of _.set, the state is mutated in place,
|
|
117
103
|
// which may cause tons of unexpected side effects for dependants.
|
|
@@ -120,7 +106,7 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
120
106
|
// avoided.
|
|
121
107
|
|
|
122
108
|
|
|
123
|
-
(
|
|
109
|
+
_set(this, p, value);
|
|
124
110
|
|
|
125
111
|
if (this.ssrContext) {
|
|
126
112
|
this.ssrContext.dirty = true;
|
|
@@ -128,15 +114,16 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
128
114
|
} else if (!this.nextNotifierId) {
|
|
129
115
|
this.nextNotifierId = setTimeout(function () {
|
|
130
116
|
_this.nextNotifierId = null;
|
|
131
|
-
|
|
117
|
+
|
|
118
|
+
_toConsumableArray(_this.watchers).forEach(function (w) {
|
|
132
119
|
return w();
|
|
133
120
|
});
|
|
134
121
|
});
|
|
135
122
|
}
|
|
136
123
|
|
|
137
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
124
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
138
125
|
/* eslint-disable no-console */
|
|
139
|
-
console.log('New state:',
|
|
126
|
+
console.log('New state:', cloneDeep(this.state));
|
|
140
127
|
console.groupEnd();
|
|
141
128
|
/* eslint-enable no-console */
|
|
142
129
|
}
|
|
@@ -186,8 +173,9 @@ var GlobalState = /*#__PURE__*/function () {
|
|
|
186
173
|
}
|
|
187
174
|
}
|
|
188
175
|
}]);
|
|
176
|
+
|
|
189
177
|
return GlobalState;
|
|
190
178
|
}();
|
|
191
179
|
|
|
192
|
-
|
|
180
|
+
export { GlobalState as default };
|
|
193
181
|
//# sourceMappingURL=GlobalState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/GlobalState.js"],"names":["cloneDeep","get","isArray","isObject","isNil","set","toPath","isDebugMode","ERR_NO_SSR_WATCH","fullPath","statePath","GlobalState","initialState","ssrContext","state","nextNotifierId","watchers","dirty","pending","process","env","NODE_ENV","msg","console","groupCollapsed","log","groupEnd","path","value","p","pos","pathSegments","i","length","seg","next","setTimeout","forEach","w","callback","Error","indexOf","pop","push"],"mappings":"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","sourcesContent":["import {\n cloneDeep,\n get,\n isArray,\n isObject,\n isNil,\n set,\n toPath,\n} from 'lodash';\n\nimport { isDebugMode } from './utils';\n\nconst ERR_NO_SSR_WATCH = 'GlobalState must not be watched at server side';\n\n/**\n * Transform state path into the full path inside GlobalState object.\n * @param {string} statePath\n * @return {string}\n * @ignore\n */\nfunction fullPath(statePath) {\n return isNil(statePath) ? 'state' : `state.${statePath}`;\n}\n\nexport default class GlobalState {\n /**\n * Creates a new global state object.\n * @param {any} [initialState] Intial global state content.\n * @param {SsrContext} [ssrContext] Server-side rendering context.\n */\n constructor(initialState, ssrContext) {\n /* eslint-disable no-param-reassign */\n this.state = cloneDeep(initialState);\n this.nextNotifierId = null;\n this.watchers = [];\n\n if (ssrContext) {\n ssrContext.dirty = false;\n ssrContext.pending = [];\n ssrContext.state = this.state;\n this.ssrContext = ssrContext;\n }\n\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n let msg = 'New ReactGlobalState created';\n if (ssrContext) msg += ' (SSR mode)';\n console.groupCollapsed(msg);\n console.log('Initial state:', cloneDeep(initialState));\n console.groupEnd();\n /* eslint-enable no-console */\n }\n /* eslint-enable no-param-reassign */\n }\n\n /**\n * Gets the value at given `path` of global state. If `path` is null or\n * undefined, the entire state object is returned.\n * @param {string} [path] Dot-delimitered state path. If not given, entire\n * global state content is returned.\n * @return {any}\n */\n get(path) {\n return get(this, fullPath(path));\n }\n\n /**\n * Writes the `value` to given global state `path`.\n * @param {string} [path] Dot-delimitered state path. If not given, entire\n * global state content is replaced by the `value`.\n * @param {any} value The value.\n * @return {any} Given `value` itself.\n */\n set(path, value) {\n const p = fullPath(path);\n if (value !== get(this, p)) {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupCollapsed(\n `ReactGlobalState update. Path: \"${path || ''}\"`,\n );\n console.log('New value:', cloneDeep(value));\n /* eslint-enable no-console */\n }\n let pos = this;\n const pathSegments = toPath(p);\n for (let i = 0; i < pathSegments.length - 1; i += 1) {\n const seg = pathSegments[i];\n const next = pos[seg];\n if (isArray(next)) pos[seg] = [...next];\n else if (isObject(next)) pos[seg] = { ...next };\n else break;\n pos = pos[seg];\n }\n\n // TODO: With such naive use of _.set, the state is mutated in place,\n // which may cause tons of unexpected side effects for dependants.\n // It will be better to partially clone the state, so that any existing\n // references are not mutated, while the full deep clonning is also\n // avoided.\n set(this, p, value);\n\n if (this.ssrContext) {\n this.ssrContext.dirty = true;\n this.ssrContext.state = this.state;\n } else if (!this.nextNotifierId) {\n this.nextNotifierId = setTimeout(() => {\n this.nextNotifierId = null;\n [...this.watchers].forEach((w) => w());\n });\n }\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.log('New state:', cloneDeep(this.state));\n console.groupEnd();\n /* eslint-enable no-console */\n }\n }\n return value;\n }\n\n /**\n * Unsubscribes `callback` from watching state updates; no operation if\n * `callback` is not subscribed to the state updates.\n * @param {function} callback\n * @throws if {@link SsrContext} is attached to the state instance: the state\n * watching functionality is intended for client-side (non-SSR) only.\n */\n unWatch(callback) {\n if (this.ssrContext) throw new Error(ERR_NO_SSR_WATCH);\n const { watchers } = this;\n const pos = watchers.indexOf(callback);\n if (pos >= 0) {\n watchers[pos] = watchers[watchers.length - 1];\n watchers.pop();\n }\n }\n\n /**\n * Subscribes `callback` to watch state updates; no operation if\n * `callback` is already subscribed to this state instance.\n * @param {function} callback It will be called without any arguments every\n * time the state content changes (note, howhever, separate state updates can\n * be applied to the state at once, and watching callbacks will be called once\n * after such bulk update).\n * @throws if {@link SsrContext} is attached to the state instance: the state\n * watching functionality is intended for client-side (non-SSR) only.\n */\n watch(callback) {\n if (this.ssrContext) throw new Error(ERR_NO_SSR_WATCH);\n const { watchers } = this;\n if (watchers.indexOf(callback) < 0) {\n watchers.push(callback);\n }\n }\n}\n"],"file":"GlobalState.js"}
|
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = GlobalStateProvider;
|
|
9
|
-
exports.getGlobalState = getGlobalState;
|
|
10
|
-
exports.getSsrContext = getSsrContext;
|
|
11
|
-
|
|
12
|
-
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
|
-
|
|
14
|
-
var _react = require("react");
|
|
15
|
-
|
|
16
|
-
var _GlobalState = _interopRequireDefault(require("./GlobalState"));
|
|
17
|
-
|
|
18
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
19
2
|
|
|
20
3
|
/* eslint-disable react/prop-types */
|
|
21
|
-
|
|
4
|
+
import { createContext, useContext, useState } from 'react';
|
|
5
|
+
import GlobalState from "./GlobalState";
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
var context = /*#__PURE__*/createContext();
|
|
22
8
|
/**
|
|
23
9
|
* Gets {@link GlobalState} instance from the context. In most cases
|
|
24
10
|
* you should use {@link useGlobalState}, and other hooks to interact with
|
|
@@ -26,7 +12,7 @@ var context = /*#__PURE__*/(0, _react.createContext)();
|
|
|
26
12
|
* @return {GlobalState}
|
|
27
13
|
*/
|
|
28
14
|
|
|
29
|
-
function getGlobalState() {
|
|
15
|
+
export function getGlobalState() {
|
|
30
16
|
// Here Rules of Hooks are violated because "getGlobalState()" does not follow
|
|
31
17
|
// convention that hook names should start with use... This is intentional in
|
|
32
18
|
// our case, as getGlobalState() hook is intended for advance scenarious,
|
|
@@ -34,7 +20,7 @@ function getGlobalState() {
|
|
|
34
20
|
// another hook, useGlobalState().
|
|
35
21
|
|
|
36
22
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
37
|
-
var globalState =
|
|
23
|
+
var globalState = useContext(context);
|
|
38
24
|
/* eslint-enable react-hooks/rules-of-hooks */
|
|
39
25
|
|
|
40
26
|
if (!globalState) throw new Error('Missing GlobalStateProvider');
|
|
@@ -55,8 +41,7 @@ function getGlobalState() {
|
|
|
55
41
|
* to the global state provided by {@link <GlobalStateProvider>}.
|
|
56
42
|
*/
|
|
57
43
|
|
|
58
|
-
|
|
59
|
-
function getSsrContext() {
|
|
44
|
+
export function getSsrContext() {
|
|
60
45
|
var throwWithoutSsrContext = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
61
46
|
|
|
62
47
|
var _getGlobalState = getGlobalState(),
|
|
@@ -82,8 +67,7 @@ function getSsrContext() {
|
|
|
82
67
|
* - If not given, a new `GlobalState` instance will be created and used.
|
|
83
68
|
*/
|
|
84
69
|
|
|
85
|
-
|
|
86
|
-
function GlobalStateProvider(_ref) {
|
|
70
|
+
export default function GlobalStateProvider(_ref) {
|
|
87
71
|
var children = _ref.children,
|
|
88
72
|
initialState = _ref.initialState,
|
|
89
73
|
ssrContext = _ref.ssrContext,
|
|
@@ -95,16 +79,16 @@ function GlobalStateProvider(_ref) {
|
|
|
95
79
|
|
|
96
80
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
97
81
|
|
|
98
|
-
if (stateProxy instanceof
|
|
99
|
-
var _useState =
|
|
82
|
+
if (stateProxy instanceof GlobalState) state = stateProxy;else if (stateProxy) state = getGlobalState();else {
|
|
83
|
+
var _useState = useState(new GlobalState(initialState, ssrContext));
|
|
100
84
|
|
|
101
|
-
var _useState2 = (
|
|
85
|
+
var _useState2 = _slicedToArray(_useState, 1);
|
|
102
86
|
|
|
103
87
|
state = _useState2[0];
|
|
104
88
|
}
|
|
105
89
|
/* eslint-enable react-hooks/rules-of-hooks */
|
|
106
90
|
|
|
107
|
-
return /*#__PURE__*/(
|
|
91
|
+
return /*#__PURE__*/_jsx(context.Provider, {
|
|
108
92
|
value: state,
|
|
109
93
|
children: children
|
|
110
94
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/GlobalStateProvider.jsx"],"names":["createContext","useContext","useState","GlobalState","context","getGlobalState","globalState","Error","getSsrContext","throwWithoutSsrContext","ssrContext","GlobalStateProvider","children","initialState","stateProxy","state"],"mappings":";;AAAA;AAEA,SAASA,aAAT,EAAwBC,UAAxB,EAAoCC,QAApC,QAAoD,OAApD;AAEA,OAAOC,WAAP;;AAEA,IAAMC,OAAO,gBAAGJ,aAAa,EAA7B;AAEA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASK,cAAT,GAA0B;AAC/B;AACA;AACA;AACA;AACA;;AACA;AACA,MAAMC,WAAW,GAAGL,UAAU,CAACG,OAAD,CAA9B;AACA;;AACA,MAAI,CAACE,WAAL,EAAkB,MAAM,IAAIC,KAAJ,CAAU,6BAAV,CAAN;AAClB,SAAOD,WAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASE,aAAT,GAAsD;AAAA,MAA/BC,sBAA+B,uEAAN,IAAM;;AAC3D,wBAAuBJ,cAAc,EAArC;AAAA,MAAQK,UAAR,mBAAQA,UAAR;;AACA,MAAI,CAACA,UAAD,IAAeD,sBAAnB,EAA2C;AACzC,UAAM,IAAIF,KAAJ,CAAU,sBAAV,CAAN;AACD;;AACD,SAAOG,UAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,eAAe,SAASC,mBAAT,OAKZ;AAAA,MAJDC,QAIC,QAJDA,QAIC;AAAA,MAHDC,YAGC,QAHDA,YAGC;AAAA,MAFDH,UAEC,QAFDA,UAEC;AAAA,MADDI,UACC,QADDA,UACC;AACD,MAAIC,KAAJ,CADC,CAED;AACA;AACA;AACA;;AACA;;AACA,MAAID,UAAU,YAAYX,WAA1B,EAAuCY,KAAK,GAAGD,UAAR,CAAvC,KACK,IAAIA,UAAJ,EAAgBC,KAAK,GAAGV,cAAc,EAAtB,CAAhB;AAAA,oBACUH,QAAQ,CAAC,IAAIC,WAAJ,CAAgBU,YAAhB,EAA8BH,UAA9B,CAAD,CADlB;;AAAA;;AACCK,IAAAA,KADD;AAAA;AAEL;;AACA,sBACE,KAAC,OAAD,CAAS,QAAT;AAAkB,IAAA,KAAK,EAAEA,KAAzB;AAAA,cACGH;AADH,IADF;AAKD","sourcesContent":["/* eslint-disable react/prop-types */\n\nimport { createContext, useContext, useState } from 'react';\n\nimport GlobalState from './GlobalState';\n\nconst context = createContext();\n\n/**\n * Gets {@link GlobalState} instance from the context. In most cases\n * you should use {@link useGlobalState}, and other hooks to interact with\n * the global state, instead of accessing it directly.\n * @return {GlobalState}\n */\nexport function getGlobalState() {\n // Here Rules of Hooks are violated because \"getGlobalState()\" does not follow\n // convention that hook names should start with use... This is intentional in\n // our case, as getGlobalState() hook is intended for advance scenarious,\n // while the normal interaction with the global state should happen via\n // another hook, useGlobalState().\n /* eslint-disable react-hooks/rules-of-hooks */\n const globalState = useContext(context);\n /* eslint-enable react-hooks/rules-of-hooks */\n if (!globalState) throw new Error('Missing GlobalStateProvider');\n return globalState;\n}\n\n/**\n * @category Hooks\n * @desc Gets SSR context.\n * @param {boolean} [throwWithoutSsrContext=true] If `true` (default),\n * this hook will throw if no SSR context is attached to the global state;\n * set `false` to not throw in such case. In either case the hook will throw\n * if the {@link <GlobalStateProvider>} (hence the state) is missing.\n * @returns {SsrContext} SSR context.\n * @throws\n * - If current component has no parent {@link <GlobalStateProvider>}\n * in the rendered React tree.\n * - If `throwWithoutSsrContext` is `true`, and there is no SSR context attached\n * to the global state provided by {@link <GlobalStateProvider>}.\n */\nexport function getSsrContext(throwWithoutSsrContext = true) {\n const { ssrContext } = getGlobalState();\n if (!ssrContext && throwWithoutSsrContext) {\n throw new Error('No SSR context found');\n }\n return ssrContext;\n}\n\n/**\n * Provides global state to its children.\n * @prop {ReactNode} [children] Component children, which will be provided with\n * the global state, and rendered in place of the provider.\n * @prop {any} [initialState] Initial content of the global state.\n * @prop {SsrContext} [ssrContext] Server-side rendering (SSR) context.\n * @prop {boolean|GlobalState} [stateProxy] This option is useful for code\n * splitting and SSR implementation:\n * - If `true`, this provider instance will fetch and reuse the global state\n * from a parent provider.\n * - If `GlobalState` instance, it will be used by this provider.\n * - If not given, a new `GlobalState` instance will be created and used.\n */\nexport default function GlobalStateProvider({\n children,\n initialState,\n ssrContext,\n stateProxy,\n}) {\n let state;\n // Here Rules of Hooks are violated because hooks are called conditionally,\n // however we assume that these properties should not change at runtime, thus\n // the actual hook order is preserved. Probably, it should be handled better,\n // though.\n /* eslint-disable react-hooks/rules-of-hooks */\n if (stateProxy instanceof GlobalState) state = stateProxy;\n else if (stateProxy) state = getGlobalState();\n else [state] = useState(new GlobalState(initialState, ssrContext));\n /* eslint-enable react-hooks/rules-of-hooks */\n return (\n <context.Provider value={state}>\n {children}\n </context.Provider>\n );\n}\n"],"file":"GlobalStateProvider.js"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// TODO: This is a temporary polyfill for `Promise.allSettled(..)` method,
|
|
2
|
+
// which is supported natively by NodeJS >= v12.9.0. As earlier NodeJS version
|
|
3
|
+
// are still in a wide use, this polyfill is added here, and it is to be dropped
|
|
4
|
+
// some time later.
|
|
5
|
+
if (!Promise.allSettled) {
|
|
6
|
+
Promise.allSettled = function (promises) {
|
|
7
|
+
return Promise.all(promises.map(function (p) {
|
|
8
|
+
return p instanceof Promise ? p.finally(function () {
|
|
9
|
+
return null;
|
|
10
|
+
}) : p;
|
|
11
|
+
}));
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { default as GlobalStateProvider, getGlobalState, getSsrContext } from "./GlobalStateProvider";
|
|
16
|
+
export { default as useAsyncCollection } from "./useAsyncCollection";
|
|
17
|
+
export { default as useAsyncData } from "./useAsyncData";
|
|
18
|
+
export { default as useGlobalState } from "./useGlobalState";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.js"],"names":["Promise","allSettled","promises","all","map","p","finally","default","GlobalStateProvider","getGlobalState","getSsrContext","useAsyncCollection","useAsyncData","useGlobalState"],"mappings":"AAAA;AACA;AACA;AACA;AACA,IAAI,CAACA,OAAO,CAACC,UAAb,EAAyB;AACvBD,EAAAA,OAAO,CAACC,UAAR,GAAqB,UAACC,QAAD;AAAA,WAAcF,OAAO,CAACG,GAAR,CACjCD,QAAQ,CAACE,GAAT,CAAa,UAACC,CAAD;AAAA,aAAQA,CAAC,YAAYL,OAAb,GAAuBK,CAAC,CAACC,OAAF,CAAU;AAAA,eAAM,IAAN;AAAA,OAAV,CAAvB,GAA+CD,CAAvD;AAAA,KAAb,CADiC,CAAd;AAAA,GAArB;AAGD;;AAED,SACEE,OAAO,IAAIC,mBADb,EAEEC,cAFF,EAGEC,aAHF;AAMA,SAASH,OAAO,IAAII,kBAApB;AACA,SAASJ,OAAO,IAAIK,YAApB;AACA,SAASL,OAAO,IAAIM,cAApB","sourcesContent":["// TODO: This is a temporary polyfill for `Promise.allSettled(..)` method,\n// which is supported natively by NodeJS >= v12.9.0. As earlier NodeJS version\n// are still in a wide use, this polyfill is added here, and it is to be dropped\n// some time later.\nif (!Promise.allSettled) {\n Promise.allSettled = (promises) => Promise.all(\n promises.map((p) => (p instanceof Promise ? p.finally(() => null) : p)),\n );\n}\n\nexport {\n default as GlobalStateProvider,\n getGlobalState,\n getSsrContext,\n} from './GlobalStateProvider';\n\nexport { default as useAsyncCollection } from './useAsyncCollection';\nexport { default as useAsyncData } from './useAsyncData';\nexport { default as useGlobalState } from './useGlobalState';\n"],"file":"index.js"}
|
|
@@ -1,18 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = useAsyncCollection;
|
|
9
|
-
|
|
10
|
-
var _useAsyncData = _interopRequireDefault(require("./useAsyncData"));
|
|
11
|
-
|
|
12
1
|
/**
|
|
13
2
|
* Loads and uses an item in an async collection.
|
|
14
3
|
*/
|
|
15
|
-
|
|
4
|
+
import useAsyncData from "./useAsyncData";
|
|
16
5
|
/**
|
|
17
6
|
* Resolves and stores at the given `path` of global state elements of
|
|
18
7
|
* an asynchronous data collection. In other words, it is an auxiliar wrapper
|
|
@@ -59,10 +48,11 @@ var _useAsyncData = _interopRequireDefault(require("./useAsyncData"));
|
|
|
59
48
|
* _e.g._ {@link useGlobalState}, but doing so you may interfere with related
|
|
60
49
|
* `useAsyncData()` hooks logic.
|
|
61
50
|
*/
|
|
62
|
-
|
|
51
|
+
|
|
52
|
+
export default function useAsyncCollection(id, path, loader) {
|
|
63
53
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
64
54
|
var itemPath = path ? "".concat(path, ".").concat(id) : id;
|
|
65
|
-
return (
|
|
55
|
+
return useAsyncData(itemPath, function (oldData) {
|
|
66
56
|
return loader(id, oldData);
|
|
67
57
|
}, options);
|
|
68
58
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/useAsyncCollection.js"],"names":["useAsyncData","useAsyncCollection","id","path","loader","options","itemPath","oldData"],"mappings":"AAAA;AACA;AACA;AAEA,OAAOA,YAAP;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,eAAe,SAASC,kBAAT,CACbC,EADa,EAEbC,IAFa,EAGbC,MAHa,EAKb;AAAA,MADAC,OACA,uEADU,EACV;AACA,MAAMC,QAAQ,GAAGH,IAAI,aAAMA,IAAN,cAAcD,EAAd,IAAqBA,EAA1C;AACA,SAAOF,YAAY,CAACM,QAAD,EAAW,UAACC,OAAD;AAAA,WAAaH,MAAM,CAACF,EAAD,EAAKK,OAAL,CAAnB;AAAA,GAAX,EAA6CF,OAA7C,CAAnB;AACD","sourcesContent":["/**\n * Loads and uses an item in an async collection.\n */\n\nimport useAsyncData from './useAsyncData';\n\n/**\n * Resolves and stores at the given `path` of global state elements of\n * an asynchronous data collection. In other words, it is an auxiliar wrapper\n * around {@link useAsyncData}, which uses a loader which resolves to different\n * data, based on ID argument passed in, and stores data fetched for different\n * IDs in the state.\n * @param {string} id ID of the collection item to load & use.\n * @param {string} path The global state path where entire collection should be\n * stored.\n * @param {AsyncCollectionLoader} loader A loader function, which takes an\n * ID of data to load, and resolves to the corresponding data.\n * @param {object} [options] Additional options.\n * @param {any[]} [options.deps=[]] An array of dependencies, which trigger\n * data reload when changed. Given dependency changes are watched shallowly\n * (similarly to the standard React's\n * [useEffect()](https://reactjs.org/docs/hooks-reference.html#useeffect)).\n * @param {boolean} [options.noSSR] If `true`, this hook won't load data during\n * server-side rendering.\n * @param {number} [options.garbageCollectAge=maxage] The maximum age of data\n * (in milliseconds), after which they are dropped from the state when the last\n * component referencing them via `useAsyncData()` hook unmounts. Defaults to\n * `maxage` option value.\n * @param {number} [options.maxage=5 x 60 x 1000] The maximum age of\n * data (in milliseconds) acceptable to the hook's caller. If loaded data are\n * older than this value, `null` is returned instead. Defaults to 5 minutes.\n * @param {number} [options.refreshAge=maxage] The maximum age of data\n * (in milliseconds), after which their refreshment will be triggered when\n * any component referencing them via `useAsyncData()` hook (re-)renders.\n * Defaults to `maxage` value.\n * @return {{\n * data: any,\n * loading: boolean,\n * timestamp: number\n * }} Returns an object with three fields: `data` holds the actual result of\n * last `loader` invokation, if any, and if satisfies `maxage` limit; `loading`\n * is a boolean flag, which is `true` if data are being loaded (the hook is\n * waiting for `loader` function resolution); `timestamp` (in milliseconds)\n * is Unix timestamp of related data currently loaded into the global state.\n *\n * Note that loaded data, if any, are stored at the given `path` of global state\n * along with related meta-information, using slightly different state segment\n * structure (see {@link AsyncDataEnvelope}). That segment of the global state\n * can be accessed, and even modified using other hooks,\n * _e.g._ {@link useGlobalState}, but doing so you may interfere with related\n * `useAsyncData()` hooks logic.\n */\nexport default function useAsyncCollection(\n id,\n path,\n loader,\n options = {},\n) {\n const itemPath = path ? `${path}.${id}` : id;\n return useAsyncData(itemPath, (oldData) => loader(id, oldData), options);\n}\n"],"file":"useAsyncCollection.js"}
|
|
@@ -1,36 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
4
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
2
5
|
|
|
3
|
-
var
|
|
6
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
4
7
|
|
|
5
|
-
Object.defineProperty(
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = useAsyncData;
|
|
9
|
-
|
|
10
|
-
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
11
|
-
|
|
12
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
13
|
-
|
|
14
|
-
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
15
|
-
|
|
16
|
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
17
|
-
|
|
18
|
-
var _lodash = require("lodash");
|
|
19
|
-
|
|
20
|
-
var _react = require("react");
|
|
21
|
-
|
|
22
|
-
var _uuid = require("uuid");
|
|
23
|
-
|
|
24
|
-
var _GlobalStateProvider = require("./GlobalStateProvider");
|
|
25
|
-
|
|
26
|
-
var _useGlobalState3 = _interopRequireDefault(require("./useGlobalState"));
|
|
27
|
-
|
|
28
|
-
var _utils = require("./utils");
|
|
29
|
-
|
|
30
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
31
|
-
|
|
32
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
8
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
33
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Loads and uses async data into the GlobalState path.
|
|
12
|
+
*/
|
|
13
|
+
import { cloneDeep } from 'lodash';
|
|
14
|
+
import { useEffect } from 'react';
|
|
15
|
+
import { v4 as uuid } from 'uuid';
|
|
16
|
+
import { getGlobalState } from "./GlobalStateProvider";
|
|
17
|
+
import useGlobalState from "./useGlobalState";
|
|
18
|
+
import { isDebugMode } from "./utils";
|
|
34
19
|
var DEFAULT_MAXAGE = 5 * 60 * 1000; // 5 minutes.
|
|
35
20
|
|
|
36
21
|
/**
|
|
@@ -105,26 +90,26 @@ function load(_x, _x2, _x3, _x4) {
|
|
|
105
90
|
|
|
106
91
|
|
|
107
92
|
function _load() {
|
|
108
|
-
_load = (
|
|
93
|
+
_load = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(path, loader, globalState, oldData) {
|
|
109
94
|
var opIdPrefix,
|
|
110
95
|
operationId,
|
|
111
96
|
operationIdPath,
|
|
112
97
|
data,
|
|
113
98
|
state,
|
|
114
99
|
_args = arguments;
|
|
115
|
-
return
|
|
100
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
116
101
|
while (1) {
|
|
117
102
|
switch (_context.prev = _context.next) {
|
|
118
103
|
case 0:
|
|
119
104
|
opIdPrefix = _args.length > 4 && _args[4] !== undefined ? _args[4] : 'C';
|
|
120
105
|
|
|
121
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
106
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
122
107
|
/* eslint-disable no-console */
|
|
123
108
|
console.log("ReactGlobalState: useAsyncData data (re-)loading. Path: \"".concat(path || '', "\""));
|
|
124
109
|
/* eslint-enable no-console */
|
|
125
110
|
}
|
|
126
111
|
|
|
127
|
-
operationId = opIdPrefix + (
|
|
112
|
+
operationId = opIdPrefix + uuid();
|
|
128
113
|
operationIdPath = path ? "".concat(path, ".operationId") : 'operationId';
|
|
129
114
|
globalState.set(operationIdPath, operationId);
|
|
130
115
|
_context.next = 7;
|
|
@@ -135,10 +120,10 @@ function _load() {
|
|
|
135
120
|
state = globalState.get(path);
|
|
136
121
|
|
|
137
122
|
if (operationId === state.operationId) {
|
|
138
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
123
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
139
124
|
/* eslint-disable no-console */
|
|
140
125
|
console.groupCollapsed("ReactGlobalState: useAsyncData data (re-)loaded. Path: \"".concat(path || '', "\""));
|
|
141
|
-
console.log('Data:',
|
|
126
|
+
console.log('Data:', cloneDeep(data));
|
|
142
127
|
/* eslint-enable no-console */
|
|
143
128
|
}
|
|
144
129
|
|
|
@@ -148,7 +133,7 @@ function _load() {
|
|
|
148
133
|
timestamp: Date.now()
|
|
149
134
|
}));
|
|
150
135
|
|
|
151
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
136
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
152
137
|
/* eslint-disable no-console */
|
|
153
138
|
console.groupEnd();
|
|
154
139
|
/* eslint-enable no-console */
|
|
@@ -165,7 +150,7 @@ function _load() {
|
|
|
165
150
|
return _load.apply(this, arguments);
|
|
166
151
|
}
|
|
167
152
|
|
|
168
|
-
function useAsyncData(path, loader) {
|
|
153
|
+
export default function useAsyncData(path, loader) {
|
|
169
154
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
170
155
|
var garbageCollectAge = options.garbageCollectAge,
|
|
171
156
|
maxage = options.maxage,
|
|
@@ -173,15 +158,15 @@ function useAsyncData(path, loader) {
|
|
|
173
158
|
if (maxage === undefined) maxage = DEFAULT_MAXAGE;
|
|
174
159
|
if (refreshAge === undefined) refreshAge = maxage;
|
|
175
160
|
if (garbageCollectAge === undefined) garbageCollectAge = maxage;
|
|
176
|
-
var globalState =
|
|
161
|
+
var globalState = getGlobalState();
|
|
177
162
|
|
|
178
|
-
var _useGlobalState = (
|
|
163
|
+
var _useGlobalState = useGlobalState(path, {
|
|
179
164
|
data: null,
|
|
180
165
|
numRefs: 0,
|
|
181
166
|
operationId: '',
|
|
182
167
|
timestamp: 0
|
|
183
168
|
}),
|
|
184
|
-
_useGlobalState2 = (
|
|
169
|
+
_useGlobalState2 = _slicedToArray(_useGlobalState, 1),
|
|
185
170
|
localState = _useGlobalState2[0];
|
|
186
171
|
|
|
187
172
|
if (globalState.ssrContext && !options.noSSR) {
|
|
@@ -200,7 +185,7 @@ function useAsyncData(path, loader) {
|
|
|
200
185
|
//
|
|
201
186
|
// TODO: Though, maybe there is a way to refactor it into a cleaner code.
|
|
202
187
|
// The same applies to other useEffect() hooks below.
|
|
203
|
-
|
|
188
|
+
useEffect(function () {
|
|
204
189
|
// eslint-disable-line react-hooks/rules-of-hooks
|
|
205
190
|
var numRefsPath = path ? "".concat(path, ".numRefs") : 'numRefs';
|
|
206
191
|
var numRefs = globalState.get(numRefsPath);
|
|
@@ -209,7 +194,7 @@ function useAsyncData(path, loader) {
|
|
|
209
194
|
var state = globalState.get(path);
|
|
210
195
|
|
|
211
196
|
if (state.numRefs === 1 && garbageCollectAge < Date.now() - state.timestamp) {
|
|
212
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
197
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
213
198
|
/* eslint-disable no-console */
|
|
214
199
|
console.log("ReactGlobalState - useAsyncData garbage collected at path ".concat(path || ''));
|
|
215
200
|
/* eslint-enable no-console */
|
|
@@ -227,7 +212,7 @@ function useAsyncData(path, loader) {
|
|
|
227
212
|
// Data loading and refreshing.
|
|
228
213
|
|
|
229
214
|
var loadTriggered = false;
|
|
230
|
-
|
|
215
|
+
useEffect(function () {
|
|
231
216
|
// eslint-disable-line react-hooks/rules-of-hooks
|
|
232
217
|
var state = globalState.get(path);
|
|
233
218
|
|
|
@@ -237,7 +222,7 @@ function useAsyncData(path, loader) {
|
|
|
237
222
|
}
|
|
238
223
|
});
|
|
239
224
|
var deps = options.deps || [];
|
|
240
|
-
|
|
225
|
+
useEffect(function () {
|
|
241
226
|
// eslint-disable-line react-hooks/rules-of-hooks
|
|
242
227
|
if (!loadTriggered && deps.length) load(path, loader, globalState);
|
|
243
228
|
}, deps); // eslint-disable-line react-hooks/exhaustive-deps
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/useAsyncData.js"],"names":["cloneDeep","useEffect","v4","uuid","getGlobalState","useGlobalState","isDebugMode","DEFAULT_MAXAGE","load","path","loader","globalState","oldData","opIdPrefix","process","env","NODE_ENV","console","log","operationId","operationIdPath","set","get","data","state","groupCollapsed","timestamp","Date","now","groupEnd","useAsyncData","options","garbageCollectAge","maxage","refreshAge","undefined","numRefs","localState","ssrContext","noSSR","pending","push","numRefsPath","loadTriggered","charAt","deps","length","loading","Boolean"],"mappings":"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","sourcesContent":["/**\n * Loads and uses async data into the GlobalState path.\n */\n\nimport { cloneDeep } from 'lodash';\nimport { useEffect } from 'react';\nimport { v4 as uuid } from 'uuid';\n\nimport { getGlobalState } from './GlobalStateProvider';\nimport useGlobalState from './useGlobalState';\nimport { isDebugMode } from './utils';\n\nconst DEFAULT_MAXAGE = 5 * 60 * 1000; // 5 minutes.\n\n/**\n * Executes the data loading operation.\n * @param {string} path Data segment path inside the global state.\n * @param {function} loader Data loader.\n * @param {GlobalState} globalState The global state instance.\n * @param {any} [oldData] Optional. Previously fetched data, currently stored in\n * the state, if already fetched by the caller; otherwise, they will be fetched\n * by the load() function itself.\n * @param {string} [opIdPrefix='C'] operationId prefix to use, which should be\n * 'C' at the client-side (default), or 'S' at the server-side (within SSR\n * context).\n * @return {Promise} Resolves once the operation is done.\n * @ignore\n */\nasync function load(path, loader, globalState, oldData, opIdPrefix = 'C') {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.log(\n `ReactGlobalState: useAsyncData data (re-)loading. Path: \"${path || ''}\"`,\n );\n /* eslint-enable no-console */\n }\n const operationId = opIdPrefix + uuid();\n const operationIdPath = path ? `${path}.operationId` : 'operationId';\n globalState.set(operationIdPath, operationId);\n const data = await loader(oldData || globalState.get(path).data);\n const state = globalState.get(path);\n if (operationId === state.operationId) {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupCollapsed(\n `ReactGlobalState: useAsyncData data (re-)loaded. Path: \"${\n path || ''\n }\"`,\n );\n console.log('Data:', cloneDeep(data));\n /* eslint-enable no-console */\n }\n globalState.set(path, {\n ...state,\n data,\n operationId: '',\n timestamp: Date.now(),\n });\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupEnd();\n /* eslint-enable no-console */\n }\n }\n}\n\n/**\n * Resolves asynchronous data, and stores them at given `path` of global\n * state. When multiple components rely on asynchronous data at the same `path`,\n * the data are resolved once, and reused until their age is within specified\n * bounds. Once the data are stale, the hook allows to refresh them. It also\n * garbage-collects stale data from the global state when the last component\n * relying on them is unmounted.\n * @param {string} path Dot-delimitered state path, where data envelop is\n * stored.\n * @param {AsyncDataLoader} loader Asynchronous function which resolves (loads)\n * data, which should be stored at the global state `path`. When multiple\n * components\n * use `useAsyncData()` hook for the same `path`, the library assumes that all\n * hook instances are called with the same `loader` (_i.e._ whichever of these\n * loaders is used to resolve async data, the result is acceptable to be reused\n * in all related components).\n * @param {object} [options] Additional options.\n * @param {any[]} [options.deps=[]] An array of dependencies, which trigger\n * data reload when changed. Given dependency changes are watched shallowly\n * (similarly to the standard React's\n * [useEffect()](https://reactjs.org/docs/hooks-reference.html#useeffect)).\n * @param {boolean} [options.noSSR] If `true`, this hook won't load data during\n * server-side rendering.\n * @param {number} [options.garbageCollectAge=maxage] The maximum age of data\n * (in milliseconds), after which they are dropped from the state when the last\n * component referencing them via `useAsyncData()` hook unmounts. Defaults to\n * `maxage` option value.\n * @param {number} [options.maxage=5 x 60 x 1000] The maximum age of\n * data (in milliseconds) acceptable to the hook's caller. If loaded data are\n * older than this value, `null` is returned instead. Defaults to 5 minutes.\n * @param {number} [options.refreshAge=maxage] The maximum age of data\n * (in milliseconds), after which their refreshment will be triggered when\n * any component referencing them via `useAsyncData()` hook (re-)renders.\n * Defaults to `maxage` value.\n * @return {{\n * data: any,\n * loading: boolean,\n * timestamp: number\n * }} Returns an object with three fields: `data` holds the actual result of\n * last `loader` invokation, if any, and if satisfies `maxage` limit; `loading`\n * is a boolean flag, which is `true` if data are being loaded (the hook is\n * waiting for `loader` function resolution); `timestamp` (in milliseconds)\n * is Unix timestamp of related data currently loaded into the global state.\n *\n * Note that loaded data, if any, are stored at the given `path` of global state\n * along with related meta-information, using slightly different state segment\n * structure (see {@link AsyncDataEnvelope}). That segment of the global state\n * can be accessed, and even modified using other hooks,\n * _e.g._ {@link useGlobalState}, but doing so you may interfere with related\n * `useAsyncData()` hooks logic.\n */\nexport default function useAsyncData(\n path,\n loader,\n options = {},\n) {\n let { garbageCollectAge, maxage, refreshAge } = options;\n if (maxage === undefined) maxage = DEFAULT_MAXAGE;\n if (refreshAge === undefined) refreshAge = maxage;\n if (garbageCollectAge === undefined) garbageCollectAge = maxage;\n\n const globalState = getGlobalState();\n const [localState] = useGlobalState(path, {\n data: null,\n numRefs: 0,\n operationId: '',\n timestamp: 0,\n });\n\n if (globalState.ssrContext && !options.noSSR) {\n const state = globalState.get(path);\n if (!state.timestamp && !state.operationId) {\n globalState.ssrContext.pending.push(\n load(path, loader, globalState, state.data, 'S'),\n );\n }\n } else {\n // This takes care about the client-side reference counting, and garbage\n // collection.\n //\n // Note: the Rules of Hook below are violated by conditional call to a hook,\n // but as the condition is actually server-side or client-side environment,\n // it is effectively non-conditional at the runtime.\n //\n // TODO: Though, maybe there is a way to refactor it into a cleaner code.\n // The same applies to other useEffect() hooks below.\n useEffect(() => { // eslint-disable-line react-hooks/rules-of-hooks\n const numRefsPath = path ? `${path}.numRefs` : 'numRefs';\n const numRefs = globalState.get(numRefsPath);\n globalState.set(numRefsPath, numRefs + 1);\n return () => {\n const state = globalState.get(path);\n if (\n state.numRefs === 1\n && garbageCollectAge < Date.now() - state.timestamp\n ) {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.log(\n `ReactGlobalState - useAsyncData garbage collected at path ${\n path || ''\n }`,\n );\n /* eslint-enable no-console */\n }\n globalState.set(path, {\n ...state,\n data: null,\n numRefs: 0,\n timestamp: 0,\n });\n } else globalState.set(numRefsPath, state.numRefs - 1);\n };\n }, [garbageCollectAge, globalState, path]);\n\n // Note: a bunch of Rules of Hooks ignored belows because in our very\n // special case the otherwise wrong behavior is actually what we need.\n\n // Data loading and refreshing.\n let loadTriggered = false;\n useEffect(() => { // eslint-disable-line react-hooks/rules-of-hooks\n const state = globalState.get(path);\n if (refreshAge < Date.now() - state.timestamp\n && (!state.operationId || state.operationId.charAt() === 'S')) {\n load(path, loader, globalState, state.data);\n loadTriggered = true; // eslint-disable-line react-hooks/exhaustive-deps\n }\n });\n\n const deps = options.deps || [];\n useEffect(() => { // eslint-disable-line react-hooks/rules-of-hooks\n if (!loadTriggered && deps.length) load(path, loader, globalState);\n }, deps); // eslint-disable-line react-hooks/exhaustive-deps\n }\n\n return {\n data: maxage < Date.now() - localState.timestamp ? null : localState.data,\n loading: Boolean(localState.operationId),\n timestamp: localState.timestamp,\n };\n}\n"],"file":"useAsyncData.js"}
|
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = useGlobalState;
|
|
9
|
-
|
|
10
|
-
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
|
-
|
|
12
|
-
var _lodash = require("lodash");
|
|
13
|
-
|
|
14
|
-
var _react = require("react");
|
|
15
|
-
|
|
16
|
-
var _GlobalStateProvider = require("./GlobalStateProvider");
|
|
17
|
-
|
|
18
|
-
var _utils = require("./utils");
|
|
19
|
-
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
20
2
|
// Hook for updates of global state.
|
|
21
|
-
|
|
3
|
+
import { cloneDeep, isFunction, isUndefined } from 'lodash';
|
|
4
|
+
import { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { getGlobalState } from "./GlobalStateProvider";
|
|
6
|
+
import { isDebugMode } from "./utils";
|
|
22
7
|
/**
|
|
23
8
|
* The primary hook for interacting with the global state, modeled after
|
|
24
9
|
* the standard React's
|
|
@@ -69,23 +54,24 @@ var _utils = require("./utils");
|
|
|
69
54
|
* Also, similar to the standard React's state setters, `setValue()` is
|
|
70
55
|
* stable function: it does not change between component re-renders.
|
|
71
56
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
57
|
+
|
|
58
|
+
export default function useGlobalState(path, initialValue) {
|
|
59
|
+
var globalState = getGlobalState();
|
|
74
60
|
var state = globalState.get(path);
|
|
75
61
|
|
|
76
|
-
if (
|
|
77
|
-
var value =
|
|
62
|
+
if (isUndefined(state) && !isUndefined(initialValue)) {
|
|
63
|
+
var value = isFunction(initialValue) ? initialValue() : initialValue;
|
|
78
64
|
state = globalState.set(path, value);
|
|
79
65
|
}
|
|
80
66
|
|
|
81
|
-
var _useState =
|
|
67
|
+
var _useState = useState(function () {
|
|
82
68
|
return state;
|
|
83
69
|
}),
|
|
84
|
-
_useState2 = (
|
|
70
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
85
71
|
localState = _useState2[0],
|
|
86
72
|
setLocalState = _useState2[1];
|
|
87
73
|
|
|
88
|
-
|
|
74
|
+
useEffect(function () {
|
|
89
75
|
// Note: the "callback.active" flag below is needed to workaround the issue
|
|
90
76
|
// https://github.com/birdofpreyru/react-global-state/issues/33,
|
|
91
77
|
// which, unfortunately, I am not able to reproduce in test environment,
|
|
@@ -107,19 +93,19 @@ function useGlobalState(path, initialValue) {
|
|
|
107
93
|
globalState.unWatch(callback);
|
|
108
94
|
};
|
|
109
95
|
}, [globalState, localState, path]);
|
|
110
|
-
var ref =
|
|
96
|
+
var ref = useRef();
|
|
111
97
|
|
|
112
98
|
if (!ref.current) {
|
|
113
99
|
ref.current = {
|
|
114
100
|
localState: localState,
|
|
115
101
|
path: path,
|
|
116
102
|
setter: function setter(value) {
|
|
117
|
-
var newValue =
|
|
103
|
+
var newValue = isFunction(value) ? value(ref.current.localState) : value;
|
|
118
104
|
|
|
119
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
105
|
+
if (process.env.NODE_ENV !== 'production' && isDebugMode()) {
|
|
120
106
|
/* eslint-disable no-console */
|
|
121
107
|
console.groupCollapsed("ReactGlobalState - useGlobalState setter triggered for path ".concat(ref.current.path || ''));
|
|
122
|
-
console.log('New value:',
|
|
108
|
+
console.log('New value:', cloneDeep(newValue));
|
|
123
109
|
console.groupEnd();
|
|
124
110
|
/* eslint-enable no-console */
|
|
125
111
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/useGlobalState.js"],"names":["cloneDeep","isFunction","isUndefined","useEffect","useRef","useState","getGlobalState","isDebugMode","useGlobalState","path","initialValue","globalState","state","get","value","set","localState","setLocalState","callback","active","newState","watch","unWatch","ref","current","setter","newValue","process","env","NODE_ENV","console","groupCollapsed","log","groupEnd"],"mappings":"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","sourcesContent":["// Hook for updates of global state.\n\nimport { cloneDeep, isFunction, isUndefined } from 'lodash';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { getGlobalState } from './GlobalStateProvider';\nimport { isDebugMode } from './utils';\n\n/**\n * The primary hook for interacting with the global state, modeled after\n * the standard React's\n * [useState](https://reactjs.org/docs/hooks-reference.html#usestate).\n * It subscribes a component to a given `path` of global state, and provides\n * a function to update it. Each time the value at `path` changes, the hook\n * triggers re-render of its host component.\n *\n * **Note:**\n * - For performance, the library does not copy objects written to / read from\n * global state paths. You MUST NOT manually mutate returned state values,\n * or change objects already written into the global state, without explicitly\n * clonning them first yourself.\n * - State update notifications are asynchronous. When your code does multiple\n * global state updates in the same React rendering cycle, all state update\n * notifications are queued and dispatched together, after the current\n * rendering cycle. In other words, in any given rendering cycle the global\n * state values are \"fixed\", and all changes becomes visible at once in the\n * next triggered rendering pass.\n *\n * @param {string} [path] Dot-delimitered state path. It can be undefined to\n * subscribe for entire state.\n *\n * Under-the-hood state values are read and written using `lodash`\n * [_.get()](https://lodash.com/docs/4.17.15#get) and\n * [_.set()](https://lodash.com/docs/4.17.15#set) methods, thus it is safe\n * to access state paths which have not been created before.\n * @param {any} [initialValue] Initial value to set at the `path`, or its\n * factory:\n * - If a function is given, it will act similar to\n * [the lazy initial state of the standard React's useState()](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state):\n * only if the value at `path` is `undefined`, the function will be executed,\n * and the value it returns will be written to the `path`.\n * - Otherwise, the given value itself will be written to the `path`,\n * if the current value at `path` is `undefined`.\n * @return {Array} It returs an array with two elements: `[value, setValue]`:\n *\n * - The `value` is the current value at given `path`.\n *\n * - The `setValue()` is setter function to write a new value to the `path`.\n *\n * Similar to the standard React's `useState()`, it supports\n * [functional value updates](https://reactjs.org/docs/hooks-reference.html#functional-updates):\n * if `setValue()` is called with a function as argument, that function will\n * be called and its return value will be written to `path`. Otherwise,\n * the argument of `setValue()` itself is written to `path`.\n *\n * Also, similar to the standard React's state setters, `setValue()` is\n * stable function: it does not change between component re-renders.\n */\nexport default function useGlobalState(path, initialValue) {\n const globalState = getGlobalState();\n let state = globalState.get(path);\n if (isUndefined(state) && !isUndefined(initialValue)) {\n const value = isFunction(initialValue) ? initialValue() : initialValue;\n state = globalState.set(path, value);\n }\n const [\n localState,\n setLocalState,\n ] = useState(() => state);\n\n useEffect(() => {\n // Note: the \"callback.active\" flag below is needed to workaround the issue\n // https://github.com/birdofpreyru/react-global-state/issues/33,\n // which, unfortunately, I am not able to reproduce in test environment,\n // but I definitely seen it in the wild.\n const callback = () => {\n if (callback.active) {\n const newState = globalState.get(path);\n if (newState !== localState) setLocalState(() => newState);\n }\n };\n callback.active = true;\n globalState.watch(callback);\n callback();\n return () => {\n delete callback.active;\n globalState.unWatch(callback);\n };\n }, [globalState, localState, path]);\n\n const ref = useRef();\n if (!ref.current) {\n ref.current = {\n localState,\n path,\n setter: (value) => {\n const newValue = isFunction(value)\n ? value(ref.current.localState) : value;\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupCollapsed(\n `ReactGlobalState - useGlobalState setter triggered for path ${\n ref.current.path || ''\n }`,\n );\n console.log('New value:', cloneDeep(newValue));\n console.groupEnd();\n /* eslint-enable no-console */\n }\n\n globalState.set(ref.current.path, newValue);\n\n // The update of local state here is important for managed inputs:\n // if we wait until the global state change notification is delivered\n // (which happens after the next React render), React won't conserve\n // the text cursor inside the currently focused input field (the cursor\n // will jump to the field end, like if the value was changed not by\n // keyboard input).\n setLocalState(() => newValue);\n },\n };\n } else {\n ref.current.localState = localState;\n ref.current.path = path;\n }\n\n return [\n localState,\n ref.current.setter,\n ];\n}\n"],"file":"useGlobalState.js"}
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
exports.isDebugMode = isDebugMode;
|
|
8
|
-
|
|
9
1
|
// Auxiliary stuff.
|
|
10
2
|
|
|
11
3
|
/**
|
|
@@ -20,14 +12,12 @@ exports.isDebugMode = isDebugMode;
|
|
|
20
12
|
* @returns {boolean}
|
|
21
13
|
* @ignore
|
|
22
14
|
*/
|
|
23
|
-
function isDebugMode() {
|
|
15
|
+
export function isDebugMode() {
|
|
24
16
|
try {
|
|
25
17
|
return process.env.NODE_ENV !== 'production' && !!process.env.REACT_GLOBAL_STATE_DEBUG;
|
|
26
18
|
} catch (error) {
|
|
27
19
|
return false;
|
|
28
20
|
}
|
|
29
21
|
}
|
|
30
|
-
|
|
31
|
-
var _default = null;
|
|
32
|
-
exports.default = _default;
|
|
22
|
+
export default null;
|
|
33
23
|
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils.js"],"names":["isDebugMode","process","env","NODE_ENV","REACT_GLOBAL_STATE_DEBUG","error"],"mappings":"AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,WAAT,GAAuB;AAC5B,MAAI;AACF,WAAOC,OAAO,CAACC,GAAR,CAAYC,QAAZ,KAAyB,YAAzB,IACF,CAAC,CAACF,OAAO,CAACC,GAAR,CAAYE,wBADnB;AAED,GAHD,CAGE,OAAOC,KAAP,EAAc;AACd,WAAO,KAAP;AACD;AACF;AAED,eAAe,IAAf","sourcesContent":["// Auxiliary stuff.\n\n/**\n * Returns 'true' if debug logging should be performed; 'false' otherwise.\n *\n * BEWARE: The actual safeguards for the debug logging still should read\n * if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n * // Some debug logging\n * }\n * to ensure that debug code is stripped out by Webpack in production mode.\n *\n * @returns {boolean}\n * @ignore\n */\nexport function isDebugMode() {\n try {\n return process.env.NODE_ENV !== 'production'\n && !!process.env.REACT_GLOBAL_STATE_DEBUG;\n } catch (error) {\n return false;\n }\n}\n\nexport default null;\n"],"file":"utils.js"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dr.pogodin/react-global-state",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Hook-based global state for React",
|
|
5
|
-
"
|
|
5
|
+
"exports": {
|
|
6
|
+
"module": "./build/module/index.js",
|
|
7
|
+
"node": "./build/node/index.js",
|
|
8
|
+
"types": "./index.d.ts"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
|
-
"build": "rimraf build && npm run build:
|
|
11
|
+
"build": "rimraf build && npm run build:module && npm run build:node",
|
|
12
|
+
"build:module": "rimraf build/web && babel src --out-dir build/module --source-maps --config-file ./babel.module.config.js",
|
|
8
13
|
"build:node": "rimraf build/node && babel src --out-dir build/node --source-maps",
|
|
9
|
-
"build:web": "rimraf build/web && babel src --out-dir build/web --source-maps --config-file ./babel.web.config.js",
|
|
10
14
|
"jest": "jest --config jest/config.json",
|
|
11
15
|
"lint": "eslint --ext .js,.jsx .",
|
|
12
16
|
"test": "npm run lint && npm run jest"
|
|
@@ -27,32 +31,32 @@
|
|
|
27
31
|
"bugs": {
|
|
28
32
|
"url": "https://github.com/birdofpreyru/react-global-state.git/issues"
|
|
29
33
|
},
|
|
30
|
-
"homepage": "https://dr.pogodin.studio/
|
|
34
|
+
"homepage": "https://dr.pogodin.studio/docs/react-global-state/index.html",
|
|
31
35
|
"dependencies": {
|
|
32
|
-
"@babel/runtime": "^7.
|
|
36
|
+
"@babel/runtime": "^7.17.2",
|
|
33
37
|
"lodash": "^4.17.21",
|
|
34
38
|
"uuid": "^8.3.2"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
37
|
-
"@babel/cli": "^7.
|
|
38
|
-
"@babel/core": "^7.
|
|
39
|
-
"@babel/
|
|
40
|
-
"@babel/plugin
|
|
41
|
-
"@babel/
|
|
42
|
-
"@babel/
|
|
43
|
-
"babel-
|
|
44
|
-
"babel-
|
|
41
|
+
"@babel/cli": "^7.17.6",
|
|
42
|
+
"@babel/core": "^7.17.5",
|
|
43
|
+
"@babel/eslint-parser": "^7.17.0",
|
|
44
|
+
"@babel/eslint-plugin": "^7.16.5",
|
|
45
|
+
"@babel/node": "^7.16.8",
|
|
46
|
+
"@babel/plugin-transform-runtime": "^7.17.0",
|
|
47
|
+
"@babel/preset-env": "^7.16.11",
|
|
48
|
+
"@babel/preset-react": "^7.16.7",
|
|
49
|
+
"babel-jest": "^27.5.1",
|
|
45
50
|
"babel-plugin-module-resolver": "^4.1.0",
|
|
46
|
-
"eslint": "^
|
|
47
|
-
"eslint-config-airbnb": "^
|
|
51
|
+
"eslint": "^8.10.0",
|
|
52
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
48
53
|
"eslint-import-resolver-babel-module": "^5.3.1",
|
|
49
|
-
"eslint-plugin-import": "^2.25.
|
|
50
|
-
"eslint-plugin-jest": "^
|
|
51
|
-
"eslint-plugin-jsx-a11y": "^6.
|
|
52
|
-
"eslint-plugin-react": "^7.
|
|
53
|
-
"eslint-plugin-react-hooks": "^4.
|
|
54
|
-
"jest": "^27.
|
|
55
|
-
"jsdoc": "^3.6.7",
|
|
54
|
+
"eslint-plugin-import": "^2.25.4",
|
|
55
|
+
"eslint-plugin-jest": "^26.1.1",
|
|
56
|
+
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
57
|
+
"eslint-plugin-react": "^7.29.3",
|
|
58
|
+
"eslint-plugin-react-hooks": "^4.3.0",
|
|
59
|
+
"jest": "^27.5.1",
|
|
56
60
|
"mockdate": "^3.0.5",
|
|
57
61
|
"pretty": "^2.0.0",
|
|
58
62
|
"react": "^17.0.2",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/GlobalState.js"],"names":["ERR_NO_SSR_WATCH","fullPath","statePath","GlobalState","initialState","ssrContext","state","nextNotifierId","watchers","dirty","pending","process","env","NODE_ENV","msg","console","groupCollapsed","log","groupEnd","path","value","p","pos","pathSegments","i","length","seg","next","setTimeout","forEach","w","callback","Error","indexOf","pop","push"],"mappings":"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","sourcesContent":["import {\n cloneDeep,\n get,\n isArray,\n isObject,\n isNil,\n set,\n toPath,\n} from 'lodash';\n\nimport { isDebugMode } from './utils';\n\nconst ERR_NO_SSR_WATCH = 'GlobalState must not be watched at server side';\n\n/**\n * Transform state path into the full path inside GlobalState object.\n * @param {string} statePath\n * @return {string}\n * @ignore\n */\nfunction fullPath(statePath) {\n return isNil(statePath) ? 'state' : `state.${statePath}`;\n}\n\nexport default class GlobalState {\n /**\n * Creates a new global state object.\n * @param {any} [initialState] Intial global state content.\n * @param {SsrContext} [ssrContext] Server-side rendering context.\n */\n constructor(initialState, ssrContext) {\n /* eslint-disable no-param-reassign */\n this.state = cloneDeep(initialState);\n this.nextNotifierId = null;\n this.watchers = [];\n\n if (ssrContext) {\n ssrContext.dirty = false;\n ssrContext.pending = [];\n ssrContext.state = this.state;\n this.ssrContext = ssrContext;\n }\n\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n let msg = 'New ReactGlobalState created';\n if (ssrContext) msg += ' (SSR mode)';\n console.groupCollapsed(msg);\n console.log('Initial state:', cloneDeep(initialState));\n console.groupEnd();\n /* eslint-enable no-console */\n }\n /* eslint-enable no-param-reassign */\n }\n\n /**\n * Gets the value at given `path` of global state. If `path` is null or\n * undefined, the entire state object is returned.\n * @param {string} [path] Dot-delimitered state path. If not given, entire\n * global state content is returned.\n * @return {any}\n */\n get(path) {\n return get(this, fullPath(path));\n }\n\n /**\n * Writes the `value` to given global state `path`.\n * @param {string} [path] Dot-delimitered state path. If not given, entire\n * global state content is replaced by the `value`.\n * @param {any} value The value.\n * @return {any} Given `value` itself.\n */\n set(path, value) {\n const p = fullPath(path);\n if (value !== get(this, p)) {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupCollapsed(\n `ReactGlobalState update. Path: \"${path || ''}\"`,\n );\n console.log('New value:', cloneDeep(value));\n /* eslint-enable no-console */\n }\n let pos = this;\n const pathSegments = toPath(p);\n for (let i = 0; i < pathSegments.length - 1; i += 1) {\n const seg = pathSegments[i];\n const next = pos[seg];\n if (isArray(next)) pos[seg] = [...next];\n else if (isObject(next)) pos[seg] = { ...next };\n else break;\n pos = pos[seg];\n }\n\n // TODO: With such naive use of _.set, the state is mutated in place,\n // which may cause tons of unexpected side effects for dependants.\n // It will be better to partially clone the state, so that any existing\n // references are not mutated, while the full deep clonning is also\n // avoided.\n set(this, p, value);\n\n if (this.ssrContext) {\n this.ssrContext.dirty = true;\n this.ssrContext.state = this.state;\n } else if (!this.nextNotifierId) {\n this.nextNotifierId = setTimeout(() => {\n this.nextNotifierId = null;\n [...this.watchers].forEach((w) => w());\n });\n }\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.log('New state:', cloneDeep(this.state));\n console.groupEnd();\n /* eslint-enable no-console */\n }\n }\n return value;\n }\n\n /**\n * Unsubscribes `callback` from watching state updates; no operation if\n * `callback` is not subscribed to the state updates.\n * @param {function} callback\n * @throws if {@link SsrContext} is attached to the state instance: the state\n * watching functionality is intended for client-side (non-SSR) only.\n */\n unWatch(callback) {\n if (this.ssrContext) throw new Error(ERR_NO_SSR_WATCH);\n const { watchers } = this;\n const pos = watchers.indexOf(callback);\n if (pos >= 0) {\n watchers[pos] = watchers[watchers.length - 1];\n watchers.pop();\n }\n }\n\n /**\n * Subscribes `callback` to watch state updates; no operation if\n * `callback` is already subscribed to this state instance.\n * @param {function} callback It will be called without any arguments every\n * time the state content changes (note, howhever, separate state updates can\n * be applied to the state at once, and watching callbacks will be called once\n * after such bulk update).\n * @throws if {@link SsrContext} is attached to the state instance: the state\n * watching functionality is intended for client-side (non-SSR) only.\n */\n watch(callback) {\n if (this.ssrContext) throw new Error(ERR_NO_SSR_WATCH);\n const { watchers } = this;\n if (watchers.indexOf(callback) < 0) {\n watchers.push(callback);\n }\n }\n}\n"],"file":"GlobalState.js"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/GlobalStateProvider.jsx"],"names":["context","getGlobalState","globalState","Error","getSsrContext","throwWithoutSsrContext","ssrContext","GlobalStateProvider","children","initialState","stateProxy","state","GlobalState"],"mappings":";;;;;;;;;;;;;AAEA;;AAEA;;;;AAJA;AAMA,IAAMA,OAAO,gBAAG,2BAAhB;AAEA;AACA;AACA;AACA;AACA;AACA;;AACO,SAASC,cAAT,GAA0B;AAC/B;AACA;AACA;AACA;AACA;;AACA;AACA,MAAMC,WAAW,GAAG,uBAAWF,OAAX,CAApB;AACA;;AACA,MAAI,CAACE,WAAL,EAAkB,MAAM,IAAIC,KAAJ,CAAU,6BAAV,CAAN;AAClB,SAAOD,WAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,SAASE,aAAT,GAAsD;AAAA,MAA/BC,sBAA+B,uEAAN,IAAM;;AAC3D,wBAAuBJ,cAAc,EAArC;AAAA,MAAQK,UAAR,mBAAQA,UAAR;;AACA,MAAI,CAACA,UAAD,IAAeD,sBAAnB,EAA2C;AACzC,UAAM,IAAIF,KAAJ,CAAU,sBAAV,CAAN;AACD;;AACD,SAAOG,UAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACe,SAASC,mBAAT,OAKZ;AAAA,MAJDC,QAIC,QAJDA,QAIC;AAAA,MAHDC,YAGC,QAHDA,YAGC;AAAA,MAFDH,UAEC,QAFDA,UAEC;AAAA,MADDI,UACC,QADDA,UACC;AACD,MAAIC,KAAJ,CADC,CAED;AACA;AACA;AACA;;AACA;;AACA,MAAID,UAAU,YAAYE,oBAA1B,EAAuCD,KAAK,GAAGD,UAAR,CAAvC,KACK,IAAIA,UAAJ,EAAgBC,KAAK,GAAGV,cAAc,EAAtB,CAAhB;AAAA,oBACU,qBAAS,IAAIW,oBAAJ,CAAgBH,YAAhB,EAA8BH,UAA9B,CAAT,CADV;;AAAA;;AACCK,IAAAA,KADD;AAAA;AAEL;;AACA,sBACE,qBAAC,OAAD,CAAS,QAAT;AAAkB,IAAA,KAAK,EAAEA,KAAzB;AAAA,cACGH;AADH,IADF;AAKD","sourcesContent":["/* eslint-disable react/prop-types */\n\nimport { createContext, useContext, useState } from 'react';\n\nimport GlobalState from './GlobalState';\n\nconst context = createContext();\n\n/**\n * Gets {@link GlobalState} instance from the context. In most cases\n * you should use {@link useGlobalState}, and other hooks to interact with\n * the global state, instead of accessing it directly.\n * @return {GlobalState}\n */\nexport function getGlobalState() {\n // Here Rules of Hooks are violated because \"getGlobalState()\" does not follow\n // convention that hook names should start with use... This is intentional in\n // our case, as getGlobalState() hook is intended for advance scenarious,\n // while the normal interaction with the global state should happen via\n // another hook, useGlobalState().\n /* eslint-disable react-hooks/rules-of-hooks */\n const globalState = useContext(context);\n /* eslint-enable react-hooks/rules-of-hooks */\n if (!globalState) throw new Error('Missing GlobalStateProvider');\n return globalState;\n}\n\n/**\n * @category Hooks\n * @desc Gets SSR context.\n * @param {boolean} [throwWithoutSsrContext=true] If `true` (default),\n * this hook will throw if no SSR context is attached to the global state;\n * set `false` to not throw in such case. In either case the hook will throw\n * if the {@link <GlobalStateProvider>} (hence the state) is missing.\n * @returns {SsrContext} SSR context.\n * @throws\n * - If current component has no parent {@link <GlobalStateProvider>}\n * in the rendered React tree.\n * - If `throwWithoutSsrContext` is `true`, and there is no SSR context attached\n * to the global state provided by {@link <GlobalStateProvider>}.\n */\nexport function getSsrContext(throwWithoutSsrContext = true) {\n const { ssrContext } = getGlobalState();\n if (!ssrContext && throwWithoutSsrContext) {\n throw new Error('No SSR context found');\n }\n return ssrContext;\n}\n\n/**\n * Provides global state to its children.\n * @prop {ReactNode} [children] Component children, which will be provided with\n * the global state, and rendered in place of the provider.\n * @prop {any} [initialState] Initial content of the global state.\n * @prop {SsrContext} [ssrContext] Server-side rendering (SSR) context.\n * @prop {boolean|GlobalState} [stateProxy] This option is useful for code\n * splitting and SSR implementation:\n * - If `true`, this provider instance will fetch and reuse the global state\n * from a parent provider.\n * - If `GlobalState` instance, it will be used by this provider.\n * - If not given, a new `GlobalState` instance will be created and used.\n */\nexport default function GlobalStateProvider({\n children,\n initialState,\n ssrContext,\n stateProxy,\n}) {\n let state;\n // Here Rules of Hooks are violated because hooks are called conditionally,\n // however we assume that these properties should not change at runtime, thus\n // the actual hook order is preserved. Probably, it should be handled better,\n // though.\n /* eslint-disable react-hooks/rules-of-hooks */\n if (stateProxy instanceof GlobalState) state = stateProxy;\n else if (stateProxy) state = getGlobalState();\n else [state] = useState(new GlobalState(initialState, ssrContext));\n /* eslint-enable react-hooks/rules-of-hooks */\n return (\n <context.Provider value={state}>\n {children}\n </context.Provider>\n );\n}\n"],"file":"GlobalStateProvider.js"}
|
package/build/web/index.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
-
|
|
7
|
-
Object.defineProperty(exports, "__esModule", {
|
|
8
|
-
value: true
|
|
9
|
-
});
|
|
10
|
-
Object.defineProperty(exports, "GlobalStateProvider", {
|
|
11
|
-
enumerable: true,
|
|
12
|
-
get: function get() {
|
|
13
|
-
return _GlobalStateProvider.default;
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
Object.defineProperty(exports, "getGlobalState", {
|
|
17
|
-
enumerable: true,
|
|
18
|
-
get: function get() {
|
|
19
|
-
return _GlobalStateProvider.getGlobalState;
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
Object.defineProperty(exports, "getSsrContext", {
|
|
23
|
-
enumerable: true,
|
|
24
|
-
get: function get() {
|
|
25
|
-
return _GlobalStateProvider.getSsrContext;
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(exports, "useAsyncCollection", {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
get: function get() {
|
|
31
|
-
return _useAsyncCollection.default;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
Object.defineProperty(exports, "useAsyncData", {
|
|
35
|
-
enumerable: true,
|
|
36
|
-
get: function get() {
|
|
37
|
-
return _useAsyncData.default;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
Object.defineProperty(exports, "useGlobalState", {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
get: function get() {
|
|
43
|
-
return _useGlobalState.default;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
var _GlobalStateProvider = _interopRequireWildcard(require("./GlobalStateProvider"));
|
|
48
|
-
|
|
49
|
-
var _useAsyncCollection = _interopRequireDefault(require("./useAsyncCollection"));
|
|
50
|
-
|
|
51
|
-
var _useAsyncData = _interopRequireDefault(require("./useAsyncData"));
|
|
52
|
-
|
|
53
|
-
var _useGlobalState = _interopRequireDefault(require("./useGlobalState"));
|
|
54
|
-
|
|
55
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
56
|
-
|
|
57
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
58
|
-
|
|
59
|
-
// TODO: This is a temporary polyfill for `Promise.allSettled(..)` method,
|
|
60
|
-
// which is supported natively by NodeJS >= v12.9.0. As earlier NodeJS version
|
|
61
|
-
// are still in a wide use, this polyfill is added here, and it is to be dropped
|
|
62
|
-
// some time later.
|
|
63
|
-
if (!Promise.allSettled) {
|
|
64
|
-
Promise.allSettled = function (promises) {
|
|
65
|
-
return Promise.all(promises.map(function (p) {
|
|
66
|
-
return p instanceof Promise ? p.finally(function () {
|
|
67
|
-
return null;
|
|
68
|
-
}) : p;
|
|
69
|
-
}));
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
//# sourceMappingURL=index.js.map
|
package/build/web/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.js"],"names":["Promise","allSettled","promises","all","map","p","finally"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA;;AAMA;;AACA;;AACA;;;;;;AAlBA;AACA;AACA;AACA;AACA,IAAI,CAACA,OAAO,CAACC,UAAb,EAAyB;AACvBD,EAAAA,OAAO,CAACC,UAAR,GAAqB,UAACC,QAAD;AAAA,WAAcF,OAAO,CAACG,GAAR,CACjCD,QAAQ,CAACE,GAAT,CAAa,UAACC,CAAD;AAAA,aAAQA,CAAC,YAAYL,OAAb,GAAuBK,CAAC,CAACC,OAAF,CAAU;AAAA,eAAM,IAAN;AAAA,OAAV,CAAvB,GAA+CD,CAAvD;AAAA,KAAb,CADiC,CAAd;AAAA,GAArB;AAGD","sourcesContent":["// TODO: This is a temporary polyfill for `Promise.allSettled(..)` method,\n// which is supported natively by NodeJS >= v12.9.0. As earlier NodeJS version\n// are still in a wide use, this polyfill is added here, and it is to be dropped\n// some time later.\nif (!Promise.allSettled) {\n Promise.allSettled = (promises) => Promise.all(\n promises.map((p) => (p instanceof Promise ? p.finally(() => null) : p)),\n );\n}\n\nexport {\n default as GlobalStateProvider,\n getGlobalState,\n getSsrContext,\n} from './GlobalStateProvider';\n\nexport { default as useAsyncCollection } from './useAsyncCollection';\nexport { default as useAsyncData } from './useAsyncData';\nexport { default as useGlobalState } from './useGlobalState';\n"],"file":"index.js"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/useAsyncCollection.js"],"names":["useAsyncCollection","id","path","loader","options","itemPath","oldData"],"mappings":";;;;;;;;;AAIA;;AAJA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,SAASA,kBAAT,CACbC,EADa,EAEbC,IAFa,EAGbC,MAHa,EAKb;AAAA,MADAC,OACA,uEADU,EACV;AACA,MAAMC,QAAQ,GAAGH,IAAI,aAAMA,IAAN,cAAcD,EAAd,IAAqBA,EAA1C;AACA,SAAO,2BAAaI,QAAb,EAAuB,UAACC,OAAD;AAAA,WAAaH,MAAM,CAACF,EAAD,EAAKK,OAAL,CAAnB;AAAA,GAAvB,EAAyDF,OAAzD,CAAP;AACD","sourcesContent":["/**\n * Loads and uses an item in an async collection.\n */\n\nimport useAsyncData from './useAsyncData';\n\n/**\n * Resolves and stores at the given `path` of global state elements of\n * an asynchronous data collection. In other words, it is an auxiliar wrapper\n * around {@link useAsyncData}, which uses a loader which resolves to different\n * data, based on ID argument passed in, and stores data fetched for different\n * IDs in the state.\n * @param {string} id ID of the collection item to load & use.\n * @param {string} path The global state path where entire collection should be\n * stored.\n * @param {AsyncCollectionLoader} loader A loader function, which takes an\n * ID of data to load, and resolves to the corresponding data.\n * @param {object} [options] Additional options.\n * @param {any[]} [options.deps=[]] An array of dependencies, which trigger\n * data reload when changed. Given dependency changes are watched shallowly\n * (similarly to the standard React's\n * [useEffect()](https://reactjs.org/docs/hooks-reference.html#useeffect)).\n * @param {boolean} [options.noSSR] If `true`, this hook won't load data during\n * server-side rendering.\n * @param {number} [options.garbageCollectAge=maxage] The maximum age of data\n * (in milliseconds), after which they are dropped from the state when the last\n * component referencing them via `useAsyncData()` hook unmounts. Defaults to\n * `maxage` option value.\n * @param {number} [options.maxage=5 x 60 x 1000] The maximum age of\n * data (in milliseconds) acceptable to the hook's caller. If loaded data are\n * older than this value, `null` is returned instead. Defaults to 5 minutes.\n * @param {number} [options.refreshAge=maxage] The maximum age of data\n * (in milliseconds), after which their refreshment will be triggered when\n * any component referencing them via `useAsyncData()` hook (re-)renders.\n * Defaults to `maxage` value.\n * @return {{\n * data: any,\n * loading: boolean,\n * timestamp: number\n * }} Returns an object with three fields: `data` holds the actual result of\n * last `loader` invokation, if any, and if satisfies `maxage` limit; `loading`\n * is a boolean flag, which is `true` if data are being loaded (the hook is\n * waiting for `loader` function resolution); `timestamp` (in milliseconds)\n * is Unix timestamp of related data currently loaded into the global state.\n *\n * Note that loaded data, if any, are stored at the given `path` of global state\n * along with related meta-information, using slightly different state segment\n * structure (see {@link AsyncDataEnvelope}). That segment of the global state\n * can be accessed, and even modified using other hooks,\n * _e.g._ {@link useGlobalState}, but doing so you may interfere with related\n * `useAsyncData()` hooks logic.\n */\nexport default function useAsyncCollection(\n id,\n path,\n loader,\n options = {},\n) {\n const itemPath = path ? `${path}.${id}` : id;\n return useAsyncData(itemPath, (oldData) => loader(id, oldData), options);\n}\n"],"file":"useAsyncCollection.js"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/useAsyncData.js"],"names":["DEFAULT_MAXAGE","load","path","loader","globalState","oldData","opIdPrefix","process","env","NODE_ENV","console","log","operationId","operationIdPath","set","get","data","state","groupCollapsed","timestamp","Date","now","groupEnd","useAsyncData","options","garbageCollectAge","maxage","refreshAge","undefined","numRefs","localState","ssrContext","noSSR","pending","push","numRefsPath","loadTriggered","charAt","deps","length","loading","Boolean"],"mappings":"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","sourcesContent":["/**\n * Loads and uses async data into the GlobalState path.\n */\n\nimport { cloneDeep } from 'lodash';\nimport { useEffect } from 'react';\nimport { v4 as uuid } from 'uuid';\n\nimport { getGlobalState } from './GlobalStateProvider';\nimport useGlobalState from './useGlobalState';\nimport { isDebugMode } from './utils';\n\nconst DEFAULT_MAXAGE = 5 * 60 * 1000; // 5 minutes.\n\n/**\n * Executes the data loading operation.\n * @param {string} path Data segment path inside the global state.\n * @param {function} loader Data loader.\n * @param {GlobalState} globalState The global state instance.\n * @param {any} [oldData] Optional. Previously fetched data, currently stored in\n * the state, if already fetched by the caller; otherwise, they will be fetched\n * by the load() function itself.\n * @param {string} [opIdPrefix='C'] operationId prefix to use, which should be\n * 'C' at the client-side (default), or 'S' at the server-side (within SSR\n * context).\n * @return {Promise} Resolves once the operation is done.\n * @ignore\n */\nasync function load(path, loader, globalState, oldData, opIdPrefix = 'C') {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.log(\n `ReactGlobalState: useAsyncData data (re-)loading. Path: \"${path || ''}\"`,\n );\n /* eslint-enable no-console */\n }\n const operationId = opIdPrefix + uuid();\n const operationIdPath = path ? `${path}.operationId` : 'operationId';\n globalState.set(operationIdPath, operationId);\n const data = await loader(oldData || globalState.get(path).data);\n const state = globalState.get(path);\n if (operationId === state.operationId) {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupCollapsed(\n `ReactGlobalState: useAsyncData data (re-)loaded. Path: \"${\n path || ''\n }\"`,\n );\n console.log('Data:', cloneDeep(data));\n /* eslint-enable no-console */\n }\n globalState.set(path, {\n ...state,\n data,\n operationId: '',\n timestamp: Date.now(),\n });\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupEnd();\n /* eslint-enable no-console */\n }\n }\n}\n\n/**\n * Resolves asynchronous data, and stores them at given `path` of global\n * state. When multiple components rely on asynchronous data at the same `path`,\n * the data are resolved once, and reused until their age is within specified\n * bounds. Once the data are stale, the hook allows to refresh them. It also\n * garbage-collects stale data from the global state when the last component\n * relying on them is unmounted.\n * @param {string} path Dot-delimitered state path, where data envelop is\n * stored.\n * @param {AsyncDataLoader} loader Asynchronous function which resolves (loads)\n * data, which should be stored at the global state `path`. When multiple\n * components\n * use `useAsyncData()` hook for the same `path`, the library assumes that all\n * hook instances are called with the same `loader` (_i.e._ whichever of these\n * loaders is used to resolve async data, the result is acceptable to be reused\n * in all related components).\n * @param {object} [options] Additional options.\n * @param {any[]} [options.deps=[]] An array of dependencies, which trigger\n * data reload when changed. Given dependency changes are watched shallowly\n * (similarly to the standard React's\n * [useEffect()](https://reactjs.org/docs/hooks-reference.html#useeffect)).\n * @param {boolean} [options.noSSR] If `true`, this hook won't load data during\n * server-side rendering.\n * @param {number} [options.garbageCollectAge=maxage] The maximum age of data\n * (in milliseconds), after which they are dropped from the state when the last\n * component referencing them via `useAsyncData()` hook unmounts. Defaults to\n * `maxage` option value.\n * @param {number} [options.maxage=5 x 60 x 1000] The maximum age of\n * data (in milliseconds) acceptable to the hook's caller. If loaded data are\n * older than this value, `null` is returned instead. Defaults to 5 minutes.\n * @param {number} [options.refreshAge=maxage] The maximum age of data\n * (in milliseconds), after which their refreshment will be triggered when\n * any component referencing them via `useAsyncData()` hook (re-)renders.\n * Defaults to `maxage` value.\n * @return {{\n * data: any,\n * loading: boolean,\n * timestamp: number\n * }} Returns an object with three fields: `data` holds the actual result of\n * last `loader` invokation, if any, and if satisfies `maxage` limit; `loading`\n * is a boolean flag, which is `true` if data are being loaded (the hook is\n * waiting for `loader` function resolution); `timestamp` (in milliseconds)\n * is Unix timestamp of related data currently loaded into the global state.\n *\n * Note that loaded data, if any, are stored at the given `path` of global state\n * along with related meta-information, using slightly different state segment\n * structure (see {@link AsyncDataEnvelope}). That segment of the global state\n * can be accessed, and even modified using other hooks,\n * _e.g._ {@link useGlobalState}, but doing so you may interfere with related\n * `useAsyncData()` hooks logic.\n */\nexport default function useAsyncData(\n path,\n loader,\n options = {},\n) {\n let { garbageCollectAge, maxage, refreshAge } = options;\n if (maxage === undefined) maxage = DEFAULT_MAXAGE;\n if (refreshAge === undefined) refreshAge = maxage;\n if (garbageCollectAge === undefined) garbageCollectAge = maxage;\n\n const globalState = getGlobalState();\n const [localState] = useGlobalState(path, {\n data: null,\n numRefs: 0,\n operationId: '',\n timestamp: 0,\n });\n\n if (globalState.ssrContext && !options.noSSR) {\n const state = globalState.get(path);\n if (!state.timestamp && !state.operationId) {\n globalState.ssrContext.pending.push(\n load(path, loader, globalState, state.data, 'S'),\n );\n }\n } else {\n // This takes care about the client-side reference counting, and garbage\n // collection.\n //\n // Note: the Rules of Hook below are violated by conditional call to a hook,\n // but as the condition is actually server-side or client-side environment,\n // it is effectively non-conditional at the runtime.\n //\n // TODO: Though, maybe there is a way to refactor it into a cleaner code.\n // The same applies to other useEffect() hooks below.\n useEffect(() => { // eslint-disable-line react-hooks/rules-of-hooks\n const numRefsPath = path ? `${path}.numRefs` : 'numRefs';\n const numRefs = globalState.get(numRefsPath);\n globalState.set(numRefsPath, numRefs + 1);\n return () => {\n const state = globalState.get(path);\n if (\n state.numRefs === 1\n && garbageCollectAge < Date.now() - state.timestamp\n ) {\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.log(\n `ReactGlobalState - useAsyncData garbage collected at path ${\n path || ''\n }`,\n );\n /* eslint-enable no-console */\n }\n globalState.set(path, {\n ...state,\n data: null,\n numRefs: 0,\n timestamp: 0,\n });\n } else globalState.set(numRefsPath, state.numRefs - 1);\n };\n }, [garbageCollectAge, globalState, path]);\n\n // Note: a bunch of Rules of Hooks ignored belows because in our very\n // special case the otherwise wrong behavior is actually what we need.\n\n // Data loading and refreshing.\n let loadTriggered = false;\n useEffect(() => { // eslint-disable-line react-hooks/rules-of-hooks\n const state = globalState.get(path);\n if (refreshAge < Date.now() - state.timestamp\n && (!state.operationId || state.operationId.charAt() === 'S')) {\n load(path, loader, globalState, state.data);\n loadTriggered = true; // eslint-disable-line react-hooks/exhaustive-deps\n }\n });\n\n const deps = options.deps || [];\n useEffect(() => { // eslint-disable-line react-hooks/rules-of-hooks\n if (!loadTriggered && deps.length) load(path, loader, globalState);\n }, deps); // eslint-disable-line react-hooks/exhaustive-deps\n }\n\n return {\n data: maxage < Date.now() - localState.timestamp ? null : localState.data,\n loading: Boolean(localState.operationId),\n timestamp: localState.timestamp,\n };\n}\n"],"file":"useAsyncData.js"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/useGlobalState.js"],"names":["useGlobalState","path","initialValue","globalState","state","get","value","set","localState","setLocalState","callback","active","newState","watch","unWatch","ref","current","setter","newValue","process","env","NODE_ENV","console","groupCollapsed","log","groupEnd"],"mappings":"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","sourcesContent":["// Hook for updates of global state.\n\nimport { cloneDeep, isFunction, isUndefined } from 'lodash';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { getGlobalState } from './GlobalStateProvider';\nimport { isDebugMode } from './utils';\n\n/**\n * The primary hook for interacting with the global state, modeled after\n * the standard React's\n * [useState](https://reactjs.org/docs/hooks-reference.html#usestate).\n * It subscribes a component to a given `path` of global state, and provides\n * a function to update it. Each time the value at `path` changes, the hook\n * triggers re-render of its host component.\n *\n * **Note:**\n * - For performance, the library does not copy objects written to / read from\n * global state paths. You MUST NOT manually mutate returned state values,\n * or change objects already written into the global state, without explicitly\n * clonning them first yourself.\n * - State update notifications are asynchronous. When your code does multiple\n * global state updates in the same React rendering cycle, all state update\n * notifications are queued and dispatched together, after the current\n * rendering cycle. In other words, in any given rendering cycle the global\n * state values are \"fixed\", and all changes becomes visible at once in the\n * next triggered rendering pass.\n *\n * @param {string} [path] Dot-delimitered state path. It can be undefined to\n * subscribe for entire state.\n *\n * Under-the-hood state values are read and written using `lodash`\n * [_.get()](https://lodash.com/docs/4.17.15#get) and\n * [_.set()](https://lodash.com/docs/4.17.15#set) methods, thus it is safe\n * to access state paths which have not been created before.\n * @param {any} [initialValue] Initial value to set at the `path`, or its\n * factory:\n * - If a function is given, it will act similar to\n * [the lazy initial state of the standard React's useState()](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state):\n * only if the value at `path` is `undefined`, the function will be executed,\n * and the value it returns will be written to the `path`.\n * - Otherwise, the given value itself will be written to the `path`,\n * if the current value at `path` is `undefined`.\n * @return {Array} It returs an array with two elements: `[value, setValue]`:\n *\n * - The `value` is the current value at given `path`.\n *\n * - The `setValue()` is setter function to write a new value to the `path`.\n *\n * Similar to the standard React's `useState()`, it supports\n * [functional value updates](https://reactjs.org/docs/hooks-reference.html#functional-updates):\n * if `setValue()` is called with a function as argument, that function will\n * be called and its return value will be written to `path`. Otherwise,\n * the argument of `setValue()` itself is written to `path`.\n *\n * Also, similar to the standard React's state setters, `setValue()` is\n * stable function: it does not change between component re-renders.\n */\nexport default function useGlobalState(path, initialValue) {\n const globalState = getGlobalState();\n let state = globalState.get(path);\n if (isUndefined(state) && !isUndefined(initialValue)) {\n const value = isFunction(initialValue) ? initialValue() : initialValue;\n state = globalState.set(path, value);\n }\n const [\n localState,\n setLocalState,\n ] = useState(() => state);\n\n useEffect(() => {\n // Note: the \"callback.active\" flag below is needed to workaround the issue\n // https://github.com/birdofpreyru/react-global-state/issues/33,\n // which, unfortunately, I am not able to reproduce in test environment,\n // but I definitely seen it in the wild.\n const callback = () => {\n if (callback.active) {\n const newState = globalState.get(path);\n if (newState !== localState) setLocalState(() => newState);\n }\n };\n callback.active = true;\n globalState.watch(callback);\n callback();\n return () => {\n delete callback.active;\n globalState.unWatch(callback);\n };\n }, [globalState, localState, path]);\n\n const ref = useRef();\n if (!ref.current) {\n ref.current = {\n localState,\n path,\n setter: (value) => {\n const newValue = isFunction(value)\n ? value(ref.current.localState) : value;\n if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n /* eslint-disable no-console */\n console.groupCollapsed(\n `ReactGlobalState - useGlobalState setter triggered for path ${\n ref.current.path || ''\n }`,\n );\n console.log('New value:', cloneDeep(newValue));\n console.groupEnd();\n /* eslint-enable no-console */\n }\n\n globalState.set(ref.current.path, newValue);\n\n // The update of local state here is important for managed inputs:\n // if we wait until the global state change notification is delivered\n // (which happens after the next React render), React won't conserve\n // the text cursor inside the currently focused input field (the cursor\n // will jump to the field end, like if the value was changed not by\n // keyboard input).\n setLocalState(() => newValue);\n },\n };\n } else {\n ref.current.localState = localState;\n ref.current.path = path;\n }\n\n return [\n localState,\n ref.current.setter,\n ];\n}\n"],"file":"useGlobalState.js"}
|
package/build/web/utils.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils.js"],"names":["isDebugMode","process","env","NODE_ENV","REACT_GLOBAL_STATE_DEBUG","error"],"mappings":";;;;;;;;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,WAAT,GAAuB;AAC5B,MAAI;AACF,WAAOC,OAAO,CAACC,GAAR,CAAYC,QAAZ,KAAyB,YAAzB,IACF,CAAC,CAACF,OAAO,CAACC,GAAR,CAAYE,wBADnB;AAED,GAHD,CAGE,OAAOC,KAAP,EAAc;AACd,WAAO,KAAP;AACD;AACF;;eAEc,I","sourcesContent":["// Auxiliary stuff.\n\n/**\n * Returns 'true' if debug logging should be performed; 'false' otherwise.\n *\n * BEWARE: The actual safeguards for the debug logging still should read\n * if (process.env.NODE_ENV !== 'production' && isDebugMode()) {\n * // Some debug logging\n * }\n * to ensure that debug code is stripped out by Webpack in production mode.\n *\n * @returns {boolean}\n * @ignore\n */\nexport function isDebugMode() {\n try {\n return process.env.NODE_ENV !== 'production'\n && !!process.env.REACT_GLOBAL_STATE_DEBUG;\n } catch (error) {\n return false;\n }\n}\n\nexport default null;\n"],"file":"utils.js"}
|
package/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Exposes the build for NodeJS LTS for Node environment, and web build for
|
|
3
|
-
* other environments.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/* eslint-disable global-require, no-eval */
|
|
7
|
-
|
|
8
|
-
let lib;
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
lib = process.versions.node && eval('require')('./build/node');
|
|
12
|
-
} catch (error) {
|
|
13
|
-
lib = undefined;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (!lib) lib = require('./build/web');
|
|
17
|
-
|
|
18
|
-
module.exports = lib;
|
package/node.js
DELETED