recoil-next 0.3.0 → 0.4.4
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/LICENSE +21 -0
- package/README.md +58 -53
- package/dist/index.cjs +81 -51
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.mjs +81 -51
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +17 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,93 +1,98 @@
|
|
|
1
|
-
# Recoil
|
|
1
|
+
# Recoil-Next
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/recoil-next) [](https://github.com/Mutesa-Cedric/Recoil-next/actions) [](https://github.com/Mutesa-Cedric/Recoil-next/blob/main/LICENSE) [](https://www.typescriptlang.org/)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A continuation of the Recoil state management library for React.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The official Recoil project is no longer maintained. This fork provides:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- **Cross-App Observation**: Implement persistence, routing, time-travel debugging, or undo by observing all state changes across your app, without impairing code-splitting.
|
|
9
|
+
- Active maintenance and bug fixes
|
|
10
|
+
- React 18+ compatibility
|
|
11
|
+
- Full TypeScript support
|
|
12
|
+
- Modern build tooling (Vitest, Rollup, ESLint)
|
|
14
13
|
|
|
15
14
|
## Installation
|
|
16
15
|
|
|
17
|
-
```
|
|
16
|
+
```shell
|
|
18
17
|
npm install recoil-next
|
|
19
18
|
```
|
|
20
19
|
|
|
20
|
+
Or with pnpm/yarn:
|
|
21
|
+
|
|
22
|
+
```shell
|
|
23
|
+
pnpm add recoil-next
|
|
24
|
+
# or
|
|
25
|
+
yarn add recoil-next
|
|
26
|
+
```
|
|
27
|
+
|
|
21
28
|
## Quick Start
|
|
22
29
|
|
|
23
|
-
```
|
|
24
|
-
import
|
|
25
|
-
import { RecoilRoot, atom, useRecoilState } from 'recoil-next';
|
|
30
|
+
```tsx
|
|
31
|
+
import {atom, selector, useRecoilState, useRecoilValue, RecoilRoot} from 'recoil-next';
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
// Define an atom
|
|
34
|
+
const countState = atom({
|
|
35
|
+
key: 'countState',
|
|
36
|
+
default: 0,
|
|
30
37
|
});
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
+
// Define a selector
|
|
40
|
+
const doubleCountState = selector({
|
|
41
|
+
key: 'doubleCountState',
|
|
42
|
+
get: ({get}) => get(countState) * 2,
|
|
43
|
+
});
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
// Use in components
|
|
46
|
+
function Counter() {
|
|
47
|
+
const [count, setCount] = useRecoilState(countState);
|
|
48
|
+
const doubleCount = useRecoilValue(doubleCountState);
|
|
42
49
|
|
|
43
50
|
return (
|
|
44
51
|
<div>
|
|
45
|
-
<
|
|
46
|
-
<p>
|
|
52
|
+
<p>Count: {count}</p>
|
|
53
|
+
<p>Double: {doubleCount}</p>
|
|
54
|
+
<button onClick={() => setCount(count + 1)}>Increment</button>
|
|
47
55
|
</div>
|
|
48
56
|
);
|
|
49
57
|
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## API Reference
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- `useRecoilValue(state)` - Returns the state value
|
|
64
|
-
- `useSetRecoilState(state)` - Returns the state setter function
|
|
65
|
-
- `useResetRecoilState(state)` - Returns a function to reset state to default
|
|
59
|
+
// Wrap your app with RecoilRoot
|
|
60
|
+
function App() {
|
|
61
|
+
return (
|
|
62
|
+
<RecoilRoot>
|
|
63
|
+
<Counter />
|
|
64
|
+
</RecoilRoot>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
66
68
|
|
|
67
69
|
## Migration from Recoil
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
Replace `recoil` with `recoil-next` in your imports:
|
|
70
72
|
|
|
71
|
-
```
|
|
73
|
+
```javascript
|
|
72
74
|
// Before
|
|
73
|
-
import {
|
|
75
|
+
import {atom, selector, useRecoilState} from 'recoil';
|
|
74
76
|
|
|
75
77
|
// After
|
|
76
|
-
import {
|
|
78
|
+
import {atom, selector, useRecoilState} from 'recoil-next';
|
|
77
79
|
```
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
All APIs remain identical to the original Recoil library.
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
## Documentation
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
See the original Recoil documentation: https://recoiljs.org/docs/introduction/core-concepts
|
|
86
|
+
|
|
87
|
+
## Examples
|
|
84
88
|
|
|
85
|
-
|
|
89
|
+
Check out the [examples](./examples) directory for usage examples.
|
|
86
90
|
|
|
87
91
|
## Contributing
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
- [Code of Conduct](./CODE_OF_CONDUCT.md)
|
|
94
|
+
- [Contributing Guide](./CONTRIBUTING.md)
|
|
90
95
|
|
|
91
|
-
##
|
|
96
|
+
## License
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
[MIT](./LICENSE)
|
package/dist/index.cjs
CHANGED
|
@@ -13,7 +13,9 @@ function err(message) {
|
|
|
13
13
|
try {
|
|
14
14
|
throw error;
|
|
15
15
|
}
|
|
16
|
-
catch (_) {
|
|
16
|
+
catch (_) {
|
|
17
|
+
/* T-ignore */
|
|
18
|
+
}
|
|
17
19
|
}
|
|
18
20
|
return error;
|
|
19
21
|
}
|
|
@@ -114,7 +116,8 @@ class BaseLoadable {
|
|
|
114
116
|
throw err(`Loadable expected error, but in "${this.state}" state`);
|
|
115
117
|
}
|
|
116
118
|
is(other) {
|
|
117
|
-
return other.state === this.state &&
|
|
119
|
+
return (other.state === this.state &&
|
|
120
|
+
Object.is(other.contents, this.contents));
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
123
|
class ValueLoadable extends BaseLoadable {
|
|
@@ -824,7 +827,6 @@ const getNextComponentID = () => nextComponentID++;
|
|
|
824
827
|
/** React mode and feature detection helpers */
|
|
825
828
|
var _a;
|
|
826
829
|
// Access either useSyncExternalStore or unstable_useSyncExternalStore depending on React version.
|
|
827
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
828
830
|
const useSyncExternalStore =
|
|
829
831
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
830
832
|
(_a = React.useSyncExternalStore) !== null && _a !== void 0 ? _a :
|
|
@@ -835,14 +837,17 @@ let ReactRendererVersionMismatchWarnOnce = false;
|
|
|
835
837
|
function currentRendererSupportsUseSyncExternalStore() {
|
|
836
838
|
var _a;
|
|
837
839
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
838
|
-
const internals = React
|
|
840
|
+
const internals = React
|
|
841
|
+
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
839
842
|
if (!internals)
|
|
840
843
|
return false;
|
|
841
844
|
const { ReactCurrentDispatcher, ReactCurrentOwner } = internals;
|
|
842
845
|
// The dispatcher can be on ReactCurrentDispatcher.current (newer) or ReactCurrentOwner.currentDispatcher (older)
|
|
843
846
|
const dispatcher = (_a = ReactCurrentDispatcher === null || ReactCurrentDispatcher === void 0 ? void 0 : ReactCurrentDispatcher.current) !== null && _a !== void 0 ? _a : ReactCurrentOwner === null || ReactCurrentOwner === void 0 ? void 0 : ReactCurrentOwner.currentDispatcher;
|
|
844
847
|
const isSupported = (dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.useSyncExternalStore) != null;
|
|
845
|
-
if (useSyncExternalStore !== undefined &&
|
|
848
|
+
if (useSyncExternalStore !== undefined &&
|
|
849
|
+
!isSupported &&
|
|
850
|
+
!ReactRendererVersionMismatchWarnOnce) {
|
|
846
851
|
ReactRendererVersionMismatchWarnOnce = true;
|
|
847
852
|
recoverableViolation('A React renderer without React 18+ API support is being used with React 18+.');
|
|
848
853
|
}
|
|
@@ -893,7 +898,8 @@ writes) {
|
|
|
893
898
|
return result;
|
|
894
899
|
}
|
|
895
900
|
function writeLoadableToTreeState(state, key, loadable) {
|
|
896
|
-
if (loadable.state === 'hasValue' &&
|
|
901
|
+
if (loadable.state === 'hasValue' &&
|
|
902
|
+
loadable.contents instanceof DefaultValue) {
|
|
897
903
|
state.atomValues.delete(key);
|
|
898
904
|
}
|
|
899
905
|
else {
|
|
@@ -929,7 +935,8 @@ function notifyComponents$2(store, treeState) {
|
|
|
929
935
|
}
|
|
930
936
|
}
|
|
931
937
|
function valueFromValueOrUpdater(store, state, recoilValue, valueOrUpdater) {
|
|
932
|
-
if (typeof valueOrUpdater === 'function' &&
|
|
938
|
+
if (typeof valueOrUpdater === 'function' &&
|
|
939
|
+
valueOrUpdater !== DEFAULT_VALUE) {
|
|
933
940
|
// Updater form: pass in the current value
|
|
934
941
|
const current = getRecoilValueAsLoadable(store, recoilValue, state);
|
|
935
942
|
if (current.state === 'loading') {
|
|
@@ -2382,8 +2389,7 @@ function* concatIterables(iters) {
|
|
|
2382
2389
|
* TypeScript port of Recoil_Environment.js
|
|
2383
2390
|
*/
|
|
2384
2391
|
const isSSR = typeof window === 'undefined';
|
|
2385
|
-
const isWindow = (value) => !isSSR &&
|
|
2386
|
-
(value === window || value instanceof Window);
|
|
2392
|
+
const isWindow = (value) => !isSSR && (value === window || value instanceof Window);
|
|
2387
2393
|
const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
2388
2394
|
|
|
2389
2395
|
/**
|
|
@@ -2453,7 +2459,8 @@ class Snapshot {
|
|
|
2453
2459
|
? recoilValues.values()
|
|
2454
2460
|
: opt.isInitialized === true
|
|
2455
2461
|
? recoilValuesForKeys(concatIterables([knownAtoms, knownSelectors]))
|
|
2456
|
-
: filterIterable(recoilValues.values(),
|
|
2462
|
+
: filterIterable(recoilValues.values(), recoilValue => !knownAtoms.has(recoilValue.key) &&
|
|
2463
|
+
!knownSelectors.has(recoilValue.key));
|
|
2457
2464
|
};
|
|
2458
2465
|
// Report the current status of a node.
|
|
2459
2466
|
// This peeks the current state and does not affect the snapshot state at all
|
|
@@ -2618,10 +2625,7 @@ function cloneStoreState(store, treeState, bumpVersion = false) {
|
|
|
2618
2625
|
// FIXME here's a copy
|
|
2619
2626
|
// Create blank cleanup handlers for atoms so snapshots don't re-run
|
|
2620
2627
|
// atom effects.
|
|
2621
|
-
nodeCleanupFunctions: new Map(mapIterable(storeState.nodeCleanupFunctions.entries(), ([key]) => [
|
|
2622
|
-
key,
|
|
2623
|
-
() => { },
|
|
2624
|
-
])),
|
|
2628
|
+
nodeCleanupFunctions: new Map(mapIterable(storeState.nodeCleanupFunctions.entries(), ([key]) => [key, () => { }])),
|
|
2625
2629
|
};
|
|
2626
2630
|
}
|
|
2627
2631
|
// Factory to build a fresh snapshot
|
|
@@ -2634,7 +2638,7 @@ const [memoizedCloneSnapshot, invalidateMemoizedSnapshot] = memoizeOneWithArgsHa
|
|
|
2634
2638
|
var _a;
|
|
2635
2639
|
const storeState = store.getState();
|
|
2636
2640
|
const treeState = version === 'latest'
|
|
2637
|
-
? (_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree
|
|
2641
|
+
? ((_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree)
|
|
2638
2642
|
: nullthrows(storeState.previousTree);
|
|
2639
2643
|
return new Snapshot(cloneStoreState(store, treeState), store.storeID);
|
|
2640
2644
|
}, (store, version) => {
|
|
@@ -2652,7 +2656,7 @@ function cloneSnapshot(store, version = 'latest') {
|
|
|
2652
2656
|
if (process.env.NODE_ENV === 'test') {
|
|
2653
2657
|
const storeState = store.getState();
|
|
2654
2658
|
const treeState = version === 'latest'
|
|
2655
|
-
? (_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree
|
|
2659
|
+
? ((_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree)
|
|
2656
2660
|
: nullthrows(storeState.previousTree);
|
|
2657
2661
|
return new Snapshot(cloneStoreState(store, treeState), store.storeID);
|
|
2658
2662
|
}
|
|
@@ -2666,7 +2670,9 @@ function cloneSnapshot(store, version = 'latest') {
|
|
|
2666
2670
|
}
|
|
2667
2671
|
catch (retainError) {
|
|
2668
2672
|
// If checking isRetained() fails, assume it's released and create fresh
|
|
2669
|
-
if (retainError &&
|
|
2673
|
+
if (retainError &&
|
|
2674
|
+
typeof retainError === 'object' &&
|
|
2675
|
+
'message' in retainError &&
|
|
2670
2676
|
typeof retainError.message === 'string' &&
|
|
2671
2677
|
retainError.message.includes('already been released')) {
|
|
2672
2678
|
invalidateMemoizedSnapshot();
|
|
@@ -2678,7 +2684,9 @@ function cloneSnapshot(store, version = 'latest') {
|
|
|
2678
2684
|
}
|
|
2679
2685
|
catch (error) {
|
|
2680
2686
|
// If the memoized snapshot was released, create a fresh one
|
|
2681
|
-
if (error &&
|
|
2687
|
+
if (error &&
|
|
2688
|
+
typeof error === 'object' &&
|
|
2689
|
+
'message' in error &&
|
|
2682
2690
|
typeof error.message === 'string' &&
|
|
2683
2691
|
error.message.includes('already been released')) {
|
|
2684
2692
|
invalidateMemoizedSnapshot();
|
|
@@ -3229,7 +3237,7 @@ function useRecoilValueLoadable_SYNC_EXTERNAL_STORE(recoilValue) {
|
|
|
3229
3237
|
const store = storeRef.current;
|
|
3230
3238
|
const storeState = store.getState();
|
|
3231
3239
|
const treeState = reactMode().early
|
|
3232
|
-
? (_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree
|
|
3240
|
+
? ((_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree)
|
|
3233
3241
|
: storeState.currentTree;
|
|
3234
3242
|
const loadable = getRecoilValueAsLoadable(store, recoilValue, treeState);
|
|
3235
3243
|
return { loadable, key: recoilValue.key };
|
|
@@ -3253,7 +3261,7 @@ function useRecoilValueLoadable_SYNC_EXTERNAL_STORE(recoilValue) {
|
|
|
3253
3261
|
if (Recoil_gkx_OSS('recoil_memory_managament_2020')) {
|
|
3254
3262
|
updateRetainCount(store, recoilValue.key, 1);
|
|
3255
3263
|
}
|
|
3256
|
-
const subscription = subscribeToRecoilValue(store, recoilValue,
|
|
3264
|
+
const subscription = subscribeToRecoilValue(store, recoilValue, _treeState => notify());
|
|
3257
3265
|
return () => {
|
|
3258
3266
|
// Release retention when subscription is released
|
|
3259
3267
|
if (Recoil_gkx_OSS('recoil_memory_managament_2020')) {
|
|
@@ -3266,7 +3274,8 @@ function useRecoilValueLoadable_SYNC_EXTERNAL_STORE(recoilValue) {
|
|
|
3266
3274
|
if (React.useSyncExternalStore === undefined) {
|
|
3267
3275
|
throw new Error('useSyncExternalStore is not available in this version of React');
|
|
3268
3276
|
}
|
|
3269
|
-
return React.useSyncExternalStore(subscribe, getMemoizedSnapshot, () => ssrSnapshot)
|
|
3277
|
+
return React.useSyncExternalStore(subscribe, getMemoizedSnapshot, () => ssrSnapshot)
|
|
3278
|
+
.loadable;
|
|
3270
3279
|
}
|
|
3271
3280
|
function useRecoilValueLoadable_TRANSITION_SUPPORT(recoilValue) {
|
|
3272
3281
|
const storeRef = useStoreRef();
|
|
@@ -3276,7 +3285,7 @@ function useRecoilValueLoadable_TRANSITION_SUPPORT(recoilValue) {
|
|
|
3276
3285
|
const store = storeRef.current;
|
|
3277
3286
|
const storeState = store.getState();
|
|
3278
3287
|
const treeState = reactMode().early
|
|
3279
|
-
? (_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree
|
|
3288
|
+
? ((_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree)
|
|
3280
3289
|
: storeState.currentTree;
|
|
3281
3290
|
return getRecoilValueAsLoadable(store, recoilValue, treeState);
|
|
3282
3291
|
}, [storeRef, recoilValue]);
|
|
@@ -3307,7 +3316,7 @@ function useRecoilValueLoadable_LEGACY(recoilValue) {
|
|
|
3307
3316
|
const store = storeRef.current;
|
|
3308
3317
|
const storeState = store.getState();
|
|
3309
3318
|
const treeState = reactMode().early
|
|
3310
|
-
? (_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree
|
|
3319
|
+
? ((_a = storeState.nextTree) !== null && _a !== void 0 ? _a : storeState.currentTree)
|
|
3311
3320
|
: storeState.currentTree;
|
|
3312
3321
|
return getRecoilValueAsLoadable(store, recoilValue, treeState);
|
|
3313
3322
|
}, [storeRef, recoilValue]);
|
|
@@ -3448,7 +3457,9 @@ function useTransactionSubscription(callback) {
|
|
|
3448
3457
|
}
|
|
3449
3458
|
catch (error) {
|
|
3450
3459
|
// In React 19, snapshots can fail more aggressively
|
|
3451
|
-
if (error &&
|
|
3460
|
+
if (error &&
|
|
3461
|
+
typeof error === 'object' &&
|
|
3462
|
+
'message' in error &&
|
|
3452
3463
|
typeof error.message === 'string' &&
|
|
3453
3464
|
error.message.includes('already been released')) {
|
|
3454
3465
|
console.warn('Snapshot already released in transaction subscription, skipping');
|
|
@@ -3482,7 +3493,9 @@ function useRecoilSnapshot() {
|
|
|
3482
3493
|
catch (error) {
|
|
3483
3494
|
// In React 19, snapshots can be released more aggressively
|
|
3484
3495
|
// If the snapshot was already released, create a fresh one
|
|
3485
|
-
if (error &&
|
|
3496
|
+
if (error &&
|
|
3497
|
+
typeof error === 'object' &&
|
|
3498
|
+
'message' in error &&
|
|
3486
3499
|
typeof error.message === 'string' &&
|
|
3487
3500
|
error.message.includes('already been released')) {
|
|
3488
3501
|
console.warn('Snapshot already released during initial state, creating fresh snapshot');
|
|
@@ -3501,7 +3514,9 @@ function useRecoilSnapshot() {
|
|
|
3501
3514
|
catch (error) {
|
|
3502
3515
|
// In React 19, snapshots can be released more aggressively
|
|
3503
3516
|
// If the snapshot was already released, skip this update
|
|
3504
|
-
if (error &&
|
|
3517
|
+
if (error &&
|
|
3518
|
+
typeof error === 'object' &&
|
|
3519
|
+
'message' in error &&
|
|
3505
3520
|
typeof error.message === 'string' &&
|
|
3506
3521
|
error.message.includes('already been released')) {
|
|
3507
3522
|
console.warn('Snapshot already released during transaction subscription, skipping update');
|
|
@@ -3519,7 +3534,9 @@ function useRecoilSnapshot() {
|
|
|
3519
3534
|
}
|
|
3520
3535
|
catch (error) {
|
|
3521
3536
|
// If snapshot retention fails, skip this effect
|
|
3522
|
-
if (error &&
|
|
3537
|
+
if (error &&
|
|
3538
|
+
typeof error === 'object' &&
|
|
3539
|
+
'message' in error &&
|
|
3523
3540
|
typeof error.message === 'string' &&
|
|
3524
3541
|
error.message.includes('already been released')) {
|
|
3525
3542
|
console.warn('Cannot retain snapshot in useEffect, already released');
|
|
@@ -3560,7 +3577,9 @@ function useRecoilSnapshot() {
|
|
|
3560
3577
|
}
|
|
3561
3578
|
catch (error) {
|
|
3562
3579
|
// If snapshot retention fails, skip this retention
|
|
3563
|
-
if (error &&
|
|
3580
|
+
if (error &&
|
|
3581
|
+
typeof error === 'object' &&
|
|
3582
|
+
'message' in error &&
|
|
3564
3583
|
typeof error.message === 'string' &&
|
|
3565
3584
|
error.message.includes('already been released')) {
|
|
3566
3585
|
console.warn('Cannot retain snapshot in render, already released');
|
|
@@ -3608,7 +3627,10 @@ function gotoSnapshot(store, snapshot) {
|
|
|
3608
3627
|
newTree.stateID = snapshot.getID();
|
|
3609
3628
|
const atomKeysChanged = new Set();
|
|
3610
3629
|
// Update atoms that should be restored from snapshots
|
|
3611
|
-
for (const key of new Set([
|
|
3630
|
+
for (const key of new Set([
|
|
3631
|
+
...prev.atomValues.keys(),
|
|
3632
|
+
...next.atomValues.keys(),
|
|
3633
|
+
])) {
|
|
3612
3634
|
const node = getNode(key);
|
|
3613
3635
|
if (!node.shouldRestoreFromSnapshots)
|
|
3614
3636
|
continue;
|
|
@@ -3619,7 +3641,9 @@ function gotoSnapshot(store, snapshot) {
|
|
|
3619
3641
|
const loadable = next.atomValues.has(key)
|
|
3620
3642
|
? nullthrows(next.atomValues.get(key))
|
|
3621
3643
|
: loadableWithValue(DEFAULT_VALUE);
|
|
3622
|
-
if (loadable &&
|
|
3644
|
+
if (loadable &&
|
|
3645
|
+
loadable.state === 'hasValue' &&
|
|
3646
|
+
loadable.contents === DEFAULT_VALUE) {
|
|
3623
3647
|
newTree.atomValues.delete(key);
|
|
3624
3648
|
}
|
|
3625
3649
|
else {
|
|
@@ -3656,7 +3680,6 @@ function useGetRecoilValueInfo() {
|
|
|
3656
3680
|
function useRecoilBridgeAcrossReactRoots() {
|
|
3657
3681
|
const store = useStoreRef().current;
|
|
3658
3682
|
return React.useMemo(() => {
|
|
3659
|
-
// eslint-disable-next-line no-shadow
|
|
3660
3683
|
function RecoilBridge({ children }) {
|
|
3661
3684
|
return jsxRuntime.jsx(RecoilRoot, { store: store, children: children });
|
|
3662
3685
|
}
|
|
@@ -3785,7 +3808,7 @@ function recoilCallback(store, fn, args, extraInterface) {
|
|
|
3785
3808
|
// For all other methods, delegate to target
|
|
3786
3809
|
const value = target[prop];
|
|
3787
3810
|
return typeof value === 'function' ? value.bind(target) : value;
|
|
3788
|
-
}
|
|
3811
|
+
},
|
|
3789
3812
|
});
|
|
3790
3813
|
return hybridSnapshot;
|
|
3791
3814
|
},
|
|
@@ -3822,7 +3845,6 @@ function useRecoilCallback(fn, deps) {
|
|
|
3822
3845
|
},
|
|
3823
3846
|
// Don't include storeRef in deps to avoid unnecessary re-creation
|
|
3824
3847
|
// The store reference should be stable within a RecoilRoot
|
|
3825
|
-
// eslint-disable-next-line fb-www/react-hooks-deps
|
|
3826
3848
|
deps !== null && deps !== void 0 ? deps : []);
|
|
3827
3849
|
}
|
|
3828
3850
|
|
|
@@ -3867,7 +3889,7 @@ function isNode(object) {
|
|
|
3867
3889
|
if (typeof window === 'undefined') {
|
|
3868
3890
|
return false;
|
|
3869
3891
|
}
|
|
3870
|
-
const doc = object != null ? (_a = object.ownerDocument) !== null && _a !== void 0 ? _a : document : document;
|
|
3892
|
+
const doc = object != null ? ((_a = object.ownerDocument) !== null && _a !== void 0 ? _a : document) : document;
|
|
3871
3893
|
const defaultView = (_b = doc.defaultView) !== null && _b !== void 0 ? _b : window;
|
|
3872
3894
|
return !!(object != null &&
|
|
3873
3895
|
(typeof defaultView.Node === 'function'
|
|
@@ -3981,7 +4003,8 @@ function stringify(x, opt, key, visited = new Set()) {
|
|
|
3981
4003
|
if (x instanceof Map) {
|
|
3982
4004
|
const obj = {};
|
|
3983
4005
|
for (const [k, v] of x) {
|
|
3984
|
-
obj[typeof k === 'string' ? k : stringify(k, opt, undefined, visited)] =
|
|
4006
|
+
obj[typeof k === 'string' ? k : stringify(k, opt, undefined, visited)] =
|
|
4007
|
+
v;
|
|
3985
4008
|
}
|
|
3986
4009
|
const result = stringify(obj, opt, key, visited);
|
|
3987
4010
|
visited.delete(x);
|
|
@@ -4113,7 +4136,7 @@ class TreeCache {
|
|
|
4113
4136
|
// Second, setup the leaf node:
|
|
4114
4137
|
// If there is an existing leaf for this route confirm it is consistent
|
|
4115
4138
|
const oldLeaf = node
|
|
4116
|
-
? (_d = node.branches.get(branchKey)) !== null && _d !== void 0 ? _d : null
|
|
4139
|
+
? ((_d = node.branches.get(branchKey)) !== null && _d !== void 0 ? _d : null)
|
|
4117
4140
|
: this._root;
|
|
4118
4141
|
if (oldLeaf != null &&
|
|
4119
4142
|
(oldLeaf.type !== 'leaf' || oldLeaf.branchKey !== branchKey)) {
|
|
@@ -4339,9 +4362,11 @@ const defaultPolicy$1 = {
|
|
|
4339
4362
|
maxSize: Infinity,
|
|
4340
4363
|
};
|
|
4341
4364
|
function treeCacheFromPolicy(policy = defaultPolicy$1, name) {
|
|
4342
|
-
const { equality = defaultPolicy$1.equality
|
|
4365
|
+
const { equality = defaultPolicy$1.equality } = policy;
|
|
4343
4366
|
const eviction = 'eviction' in policy ? policy.eviction : 'keep-all';
|
|
4344
|
-
const maxSize = 'maxSize' in policy && policy.eviction === 'lru'
|
|
4367
|
+
const maxSize = 'maxSize' in policy && policy.eviction === 'lru'
|
|
4368
|
+
? policy.maxSize
|
|
4369
|
+
: defaultPolicy$1.maxSize;
|
|
4345
4370
|
const valueMapper = getValueMapper$1(equality);
|
|
4346
4371
|
return getTreeCache(eviction, maxSize, valueMapper, name);
|
|
4347
4372
|
}
|
|
@@ -4644,8 +4669,7 @@ function selector(options) {
|
|
|
4644
4669
|
});
|
|
4645
4670
|
}
|
|
4646
4671
|
catch (error) {
|
|
4647
|
-
throw err(`Problem with cache lookup for selector "${key}": ${error
|
|
4648
|
-
.message}`);
|
|
4672
|
+
throw err(`Problem with cache lookup for selector "${key}": ${error.message}`);
|
|
4649
4673
|
}
|
|
4650
4674
|
if (cachedLoadable) {
|
|
4651
4675
|
state.atomValues.set(key, cachedLoadable);
|
|
@@ -4750,8 +4774,7 @@ function selector(options) {
|
|
|
4750
4774
|
cache.set(depValuesToDepRoute(depValues), loadable);
|
|
4751
4775
|
}
|
|
4752
4776
|
catch (error) {
|
|
4753
|
-
throw err(`Problem with setting cache for selector "${key}": ${error
|
|
4754
|
-
.message}`);
|
|
4777
|
+
throw err(`Problem with setting cache for selector "${key}": ${error.message}`);
|
|
4755
4778
|
}
|
|
4756
4779
|
}
|
|
4757
4780
|
function detectCircularDependencies(fn) {
|
|
@@ -5047,7 +5070,8 @@ function baseAtom(options) {
|
|
|
5047
5070
|
var _a;
|
|
5048
5071
|
const { release } = store.subscribeToTransactions(currentStore => {
|
|
5049
5072
|
var _a, _b;
|
|
5050
|
-
let {
|
|
5073
|
+
let { previousTree } = currentStore.getState();
|
|
5074
|
+
const { currentTree } = currentStore.getState();
|
|
5051
5075
|
if (!previousTree) {
|
|
5052
5076
|
recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
|
|
5053
5077
|
previousTree = currentTree;
|
|
@@ -5147,7 +5171,9 @@ function baseAtom(options) {
|
|
|
5147
5171
|
function setAtom(_store, state, newValue) {
|
|
5148
5172
|
if (state.atomValues.has(key)) {
|
|
5149
5173
|
const existing = state.atomValues.get(key);
|
|
5150
|
-
if (existing &&
|
|
5174
|
+
if (existing &&
|
|
5175
|
+
existing.state === 'hasValue' &&
|
|
5176
|
+
newValue === existing.contents) {
|
|
5151
5177
|
return new Map();
|
|
5152
5178
|
}
|
|
5153
5179
|
}
|
|
@@ -5262,9 +5288,11 @@ const defaultPolicy = {
|
|
|
5262
5288
|
maxSize: Infinity,
|
|
5263
5289
|
};
|
|
5264
5290
|
function cacheFromPolicy(policy = defaultPolicy) {
|
|
5265
|
-
const { equality = defaultPolicy.equality
|
|
5291
|
+
const { equality = defaultPolicy.equality } = policy;
|
|
5266
5292
|
const eviction = 'eviction' in policy ? policy.eviction : 'keep-all';
|
|
5267
|
-
const maxSize = 'maxSize' in policy && policy.eviction === 'lru'
|
|
5293
|
+
const maxSize = 'maxSize' in policy && policy.eviction === 'lru'
|
|
5294
|
+
? policy.maxSize
|
|
5295
|
+
: defaultPolicy.maxSize;
|
|
5268
5296
|
const valueMapper = getValueMapper(equality);
|
|
5269
5297
|
const cache = getCache(eviction, maxSize, valueMapper);
|
|
5270
5298
|
return cache;
|
|
@@ -5283,7 +5311,10 @@ function getCache(eviction, maxSize, mapKey) {
|
|
|
5283
5311
|
case 'keep-all':
|
|
5284
5312
|
return new MapCache({ mapKey: mapKey });
|
|
5285
5313
|
case 'lru':
|
|
5286
|
-
return new LRUCache({
|
|
5314
|
+
return new LRUCache({
|
|
5315
|
+
mapKey: mapKey,
|
|
5316
|
+
maxSize: nullthrows(maxSize),
|
|
5317
|
+
});
|
|
5287
5318
|
case 'most-recent':
|
|
5288
5319
|
return new LRUCache({ mapKey: mapKey, maxSize: 1 });
|
|
5289
5320
|
}
|
|
@@ -5317,7 +5348,7 @@ function atomFamily(options) {
|
|
|
5317
5348
|
? options.effects(params)
|
|
5318
5349
|
: typeof options.effects_UNSTABLE === 'function'
|
|
5319
5350
|
? options.effects_UNSTABLE(params)
|
|
5320
|
-
: (_b = options.effects) !== null && _b !== void 0 ? _b : options.effects_UNSTABLE }));
|
|
5351
|
+
: ((_b = options.effects) !== null && _b !== void 0 ? _b : options.effects_UNSTABLE) }));
|
|
5321
5352
|
atomCache.set(params, newAtom);
|
|
5322
5353
|
setConfigDeletionHandler(newAtom.key, () => {
|
|
5323
5354
|
atomCache.delete(params);
|
|
@@ -5544,7 +5575,7 @@ const waitForAllSettled = selectorFamily({
|
|
|
5544
5575
|
if (exceptions.every(exp => !isPromise(exp))) {
|
|
5545
5576
|
return wrapLoadables(dependencies, results, exceptions);
|
|
5546
5577
|
}
|
|
5547
|
-
return
|
|
5578
|
+
return Promise.all(exceptions.map((exp, i) => isPromise(exp)
|
|
5548
5579
|
? exp
|
|
5549
5580
|
.then(result => {
|
|
5550
5581
|
results[i] = result;
|
|
@@ -5554,8 +5585,7 @@ const waitForAllSettled = selectorFamily({
|
|
|
5554
5585
|
results[i] = undefined;
|
|
5555
5586
|
exceptions[i] = error;
|
|
5556
5587
|
})
|
|
5557
|
-
: null))
|
|
5558
|
-
.then(() => wrapLoadables(dependencies, results, exceptions)));
|
|
5588
|
+
: null)).then(() => wrapLoadables(dependencies, results, exceptions));
|
|
5559
5589
|
},
|
|
5560
5590
|
dangerouslyAllowMutability: true,
|
|
5561
5591
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -16,7 +16,7 @@ declare abstract class BaseLoadable<T> {
|
|
|
16
16
|
is(other: Loadable<any>): boolean;
|
|
17
17
|
}
|
|
18
18
|
declare class ValueLoadable<T> extends BaseLoadable<T> {
|
|
19
|
-
state:
|
|
19
|
+
state: "hasValue";
|
|
20
20
|
contents: T;
|
|
21
21
|
constructor(value: T);
|
|
22
22
|
getValue(): T;
|
|
@@ -28,7 +28,7 @@ declare class ValueLoadable<T> extends BaseLoadable<T> {
|
|
|
28
28
|
map<S>(map: (value: T) => Promise<S> | Loadable<S> | S): Loadable<S>;
|
|
29
29
|
}
|
|
30
30
|
declare class ErrorLoadable<T> extends BaseLoadable<T> {
|
|
31
|
-
state:
|
|
31
|
+
state: "hasError";
|
|
32
32
|
contents: unknown;
|
|
33
33
|
constructor(error: unknown);
|
|
34
34
|
getValue(): T;
|
|
@@ -40,7 +40,7 @@ declare class ErrorLoadable<T> extends BaseLoadable<T> {
|
|
|
40
40
|
map<S>(_map: (value: T) => Promise<S> | Loadable<S> | S): Loadable<S>;
|
|
41
41
|
}
|
|
42
42
|
declare class LoadingLoadable<T> extends BaseLoadable<T> {
|
|
43
|
-
state:
|
|
43
|
+
state: "loading";
|
|
44
44
|
contents: Promise<T>;
|
|
45
45
|
constructor(promise: Promise<T>);
|
|
46
46
|
getValue(): T;
|
|
@@ -486,7 +486,7 @@ declare function useRecoilTransactionObserver(callback: (info: {
|
|
|
486
486
|
declare function useRecoilSnapshot(): Snapshot;
|
|
487
487
|
declare function useGotoRecoilSnapshot(): (snapshot: Snapshot) => void;
|
|
488
488
|
|
|
489
|
-
declare function useGetRecoilValueInfo():
|
|
489
|
+
declare function useGetRecoilValueInfo(): <T>(recoilValue: RecoilValue<T>) => RecoilValueInfo<T>;
|
|
490
490
|
|
|
491
491
|
declare function useRecoilRefresher<T>(recoilValue: RecoilValue<T>): () => void;
|
|
492
492
|
|
|
@@ -508,9 +508,9 @@ type AtomFamilyOptionsWithoutDefault<T, P extends Parameter> = Readonly<AtomOpti
|
|
|
508
508
|
retainedBy_UNSTABLE?: RetainedBy | ((param: P) => RetainedBy);
|
|
509
509
|
cachePolicyForParams_UNSTABLE?: CachePolicyWithoutEviction;
|
|
510
510
|
}>;
|
|
511
|
-
type AtomFamilyOptions<T, P extends Parameter> =
|
|
511
|
+
type AtomFamilyOptions<T, P extends Parameter> = Readonly<AtomFamilyOptionsWithoutDefault<T, P> & {
|
|
512
512
|
default: RecoilValue<T> | Promise<T> | Loadable<T> | WrappedValue<T> | T | ((param: P) => T | RecoilValue<T> | Promise<T> | Loadable<T> | WrappedValue<T>);
|
|
513
|
-
}>
|
|
513
|
+
}> | AtomFamilyOptionsWithoutDefault<T, P>;
|
|
514
514
|
declare function atomFamily<T, P extends Parameter>(options: AtomFamilyOptions<T, P>): (params: P) => RecoilState<T>;
|
|
515
515
|
|
|
516
516
|
/**
|