state-jet 1.0.10 β 1.0.11
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 +64 -7
- package/dist/index.cjs +88 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -8
- package/dist/index.mjs +86 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
A zero-boilerplate, ultra-fast global state management library for React. No context, reducers, or providersβjust simple reactive state.
|
|
4
4
|
|
|
5
|
+
For more details, see [here](https://statejet.netlify.app).
|
|
6
|
+
|
|
5
7
|
## π Why state-jet?
|
|
6
8
|
- β
**No Context, No Providers** β Works outside React, reducing unnecessary re-renders.
|
|
7
9
|
- β
**Automatic Re-Renders** β Only components using specific state values update.
|
|
8
10
|
- β
**Super Lightweight** β Ultra small!
|
|
9
11
|
- β
**SSR & Next.js Support** β Works on both client and server.
|
|
10
12
|
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
Documentation: https://statejet.netlify.app/docs
|
|
16
|
+
|
|
17
|
+
Tutorials: https://statejet.netlify.app/docs/category/tutorial
|
|
18
|
+
|
|
19
|
+
API Reference: https://statejet.netlify.app/docs/category/api-reference
|
|
20
|
+
|
|
11
21
|
## π Installation
|
|
12
22
|
```bash
|
|
13
23
|
npm install state-jet
|
|
@@ -29,7 +39,7 @@ function Counter() {
|
|
|
29
39
|
|
|
30
40
|
| Feature | Redux | Recoil | MobX | Jotai | Zustand | state-jet |
|
|
31
41
|
| ------------------------ | ----------- | --------- | ------------- | --------- | ---------------------- | --------------------- |
|
|
32
|
-
| Setup
|
|
42
|
+
| Easy Setup | β No | β No | β οΈ No | β No | β οΈ Minimal | β
Ultra-Minimal |
|
|
33
43
|
| Bundle Size | π Large | π Medium | β‘ Small | β‘ Small | β‘ Small | π₯ Ultra-Small |
|
|
34
44
|
| Reactivity | β οΈ Reducers | β
Atoms | β
Proxy-Based | β
Signals | β
Proxy-Based | β
Signal-Like |
|
|
35
45
|
| Renders Only Affected | β No | β
Yes | β
Yes | β
Yes | β
Yes | β
Yes |
|
|
@@ -41,12 +51,59 @@ function Counter() {
|
|
|
41
51
|
|
|
42
52
|
## β‘ Why state-jet Is More Advanced Than Zustand
|
|
43
53
|
|
|
44
|
-
**No Proxies Needed** β Zustand uses proxies for state updates, but state-jet uses signals, making it even faster.
|
|
45
|
-
**Derived State Is Automatic** β No need for selectors; state updates only trigger where necessary.
|
|
46
|
-
**Optimistic Updates & Rollback** β Unlike Zustand, state-jet has built-in support for instant UI updates and auto-revert on failures.
|
|
47
|
-
**Multi-Tab Sync** β
|
|
48
|
-
**CRDT Support** β Automatic conflict resolution for real-time apps, something even Zustand lacks.
|
|
54
|
+
- **No Proxies Needed** β Zustand uses proxies for state updates, but state-jet uses signals, making it even faster.
|
|
55
|
+
- **Derived State Is Automatic** β No need for selectors; state updates only trigger where necessary.
|
|
56
|
+
- **Optimistic Updates & Rollback** β Unlike Zustand, state-jet has built-in support for instant UI updates and auto-revert on failures.
|
|
57
|
+
- **Multi-Tab Sync** β global state persists across browser tabs and devices.
|
|
58
|
+
- **CRDT Support** β Automatic conflict resolution for real-time apps, something even Zustand lacks.
|
|
49
59
|
|
|
50
60
|
β
Conclusion
|
|
51
61
|
|
|
52
|
-
If you need the simplest, fastest, and most advanced state management solution for React, state-jet beats Redux, Recoil, MobX, Jotai, and even Zustand in performance, reactivity, and developer experience. π
|
|
62
|
+
If you need the simplest, fastest, and most advanced state management solution for React, state-jet beats Redux, Recoil, MobX, Jotai, and even Zustand in performance, reactivity, and developer experience. π
|
|
63
|
+
|
|
64
|
+
## π― Why Use `optimisticUpdate`?
|
|
65
|
+
| Feature | Without `optimisticUpdate` | With `optimisticUpdate` |
|
|
66
|
+
| ----------------------- | -------------------------- | --------------------------- |
|
|
67
|
+
| **UI Responsiveness** | Delayed (Waits for API) | Instant update (Optimistic) |
|
|
68
|
+
| **User Experience** | Slow & Janky | Fast & Smooth |
|
|
69
|
+
| **Rollback on Failure** | Manual Handling | Automatic |
|
|
70
|
+
| **Code Complexity** | High | Low |
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## π― Why Use `syncCRDT`?
|
|
74
|
+
| Feature | Without `syncCRDT` | With `syncCRDT` |
|
|
75
|
+
| ---------------------- | ------------------ | ------------------------- |
|
|
76
|
+
| **Multi-User Sync** | Possible Conflicts | β
Automatic Merging |
|
|
77
|
+
| **Real-Time Updates** | Needs Manual Fixes | β
No Data Loss |
|
|
78
|
+
| **Handles Conflicts** | Can Lose Changes | β
Merges Automatically |
|
|
79
|
+
| **Scalable for Teams** | Hard to Maintain | β
Ideal for Collaboration |
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## π― Why Use `derivedState`?
|
|
83
|
+
|
|
84
|
+
| Feature | Without `derivedState` | With `derivedState` |
|
|
85
|
+
| ------------------------- | -------------------------- | ----------------------------- |
|
|
86
|
+
| **Manual Recalculations** | β Yes (Recompute manually) | β
Automatic |
|
|
87
|
+
| **Reactivity** | β Requires `useEffect` | β
Updates only when needed |
|
|
88
|
+
| **Performance** | β Unoptimized | β
Only recalculates on change |
|
|
89
|
+
| **Code Complexity** | β High | β
Minimal |
|
|
90
|
+
|
|
91
|
+
## π― Why Use undo & redo?
|
|
92
|
+
|
|
93
|
+
| Feature | Without Undo/Redo | With Undo/Redo |
|
|
94
|
+
| ---------------------- | ----------------------- | ------------------------- |
|
|
95
|
+
| **Accidental Changes** | β Lost forever | β
Easily undone |
|
|
96
|
+
| **User Experience** | β Frustrating | β
Smooth & intuitive |
|
|
97
|
+
| **Multi-Step Editing** | β Hard to track | β
Easy to restore history |
|
|
98
|
+
| **Performance** | β Needs manual tracking | β
Automatic |
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## Contributing
|
|
102
|
+
|
|
103
|
+
Development of State-jet happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving State-jet.
|
|
104
|
+
|
|
105
|
+
- [Contributing Guide](./CONTRIBUTING.md)
|
|
106
|
+
|
|
107
|
+
### License
|
|
108
|
+
|
|
109
|
+
State-jet is [MIT licensed](./LICENSE).
|
package/dist/index.cjs
CHANGED
|
@@ -708,18 +708,40 @@ immer.applyPatches.bind(immer);
|
|
|
708
708
|
immer.createDraft.bind(immer);
|
|
709
709
|
immer.finishDraft.bind(immer);
|
|
710
710
|
|
|
711
|
-
const
|
|
712
|
-
if (typeof
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
711
|
+
const getGlobalThis = () => {
|
|
712
|
+
if (typeof globalThis === "object" && globalThis) return globalThis;
|
|
713
|
+
if (typeof self === "object" && self) return self;
|
|
714
|
+
if (typeof window === "object" && window) return window;
|
|
715
|
+
throw new Error("Unable to locate global `this`");
|
|
716
|
+
};
|
|
717
|
+
const globalObject = getGlobalThis();
|
|
718
|
+
|
|
719
|
+
const saveState = (key, value) => {
|
|
720
|
+
if (typeof globalObject !== "undefined") {
|
|
721
|
+
globalObject.localStorage.setItem(key, JSON.stringify(value));
|
|
716
722
|
}
|
|
717
723
|
};
|
|
718
|
-
const restoreState = (key) => {
|
|
719
|
-
if (typeof
|
|
720
|
-
const
|
|
721
|
-
return
|
|
724
|
+
const restoreState = (key, defaultValue) => {
|
|
725
|
+
if (typeof globalObject !== "undefined") {
|
|
726
|
+
const savedData = globalObject.localStorage.getItem(key);
|
|
727
|
+
return savedData ? JSON.parse(savedData) : defaultValue;
|
|
722
728
|
}
|
|
729
|
+
return defaultValue;
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
const encrypt = (data) => btoa(JSON.stringify(data));
|
|
733
|
+
const decrypt = (data) => JSON.parse(atob(data));
|
|
734
|
+
const saveEncryptedState = (key, value) => {
|
|
735
|
+
if (typeof globalObject !== "undefined") {
|
|
736
|
+
globalObject.localStorage.setItem(key, encrypt(value));
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
const restoreEncryptedState = (key, defaultValue) => {
|
|
740
|
+
if (typeof globalObject !== "undefined") {
|
|
741
|
+
const data = globalObject.localStorage.getItem(key);
|
|
742
|
+
return data ? decrypt(data) : defaultValue;
|
|
743
|
+
}
|
|
744
|
+
return defaultValue;
|
|
723
745
|
};
|
|
724
746
|
|
|
725
747
|
var shim = {exports: {}};
|
|
@@ -956,21 +978,16 @@ const redoState = (key) => {
|
|
|
956
978
|
}
|
|
957
979
|
};
|
|
958
980
|
|
|
959
|
-
const getGlobalThis = () => {
|
|
960
|
-
if (typeof globalThis === "object" && globalThis) return globalThis;
|
|
961
|
-
if (typeof self === "object" && self) return self;
|
|
962
|
-
if (typeof window === "object" && window) return window;
|
|
963
|
-
throw new Error("Unable to locate global `this`");
|
|
964
|
-
};
|
|
965
|
-
const globalObject = getGlobalThis();
|
|
966
|
-
|
|
967
981
|
const store = /* @__PURE__ */ new Map();
|
|
968
982
|
const pendingUpdates = /* @__PURE__ */ new Map();
|
|
969
983
|
const history = {};
|
|
970
984
|
const useStateGlobal = (key, initialValue, options) => {
|
|
971
985
|
if (!store.has(key)) {
|
|
972
986
|
store.set(key, { value: initialValue, listeners: /* @__PURE__ */ new Set() });
|
|
973
|
-
if (options == null ? void 0 : options.persist)
|
|
987
|
+
if (options == null ? void 0 : options.persist) {
|
|
988
|
+
if (options == null ? void 0 : options.encrypt) restoreEncryptedState(key, initialValue);
|
|
989
|
+
else restoreState(key, initialValue);
|
|
990
|
+
}
|
|
974
991
|
}
|
|
975
992
|
const state = store.get(key);
|
|
976
993
|
const undo = () => {
|
|
@@ -1006,7 +1023,10 @@ const useStateGlobal = (key, initialValue, options) => {
|
|
|
1006
1023
|
notifyDevTools(key2, nextValue);
|
|
1007
1024
|
measurePerformance(key2, () => {
|
|
1008
1025
|
});
|
|
1009
|
-
if (options == null ? void 0 : options.persist)
|
|
1026
|
+
if (options == null ? void 0 : options.persist) {
|
|
1027
|
+
if (options == null ? void 0 : options.encrypt) saveEncryptedState(key2, nextValue);
|
|
1028
|
+
else saveState(key2, nextValue);
|
|
1029
|
+
}
|
|
1010
1030
|
}
|
|
1011
1031
|
});
|
|
1012
1032
|
pendingUpdates.clear();
|
|
@@ -1031,9 +1051,9 @@ const useStateGlobal = (key, initialValue, options) => {
|
|
|
1031
1051
|
);
|
|
1032
1052
|
};
|
|
1033
1053
|
const set = (newValue) => {
|
|
1034
|
-
var _a
|
|
1054
|
+
var _a;
|
|
1035
1055
|
pendingUpdates.set(key, newValue);
|
|
1036
|
-
if ((
|
|
1056
|
+
if ((_a = globalObject) == null ? void 0 : _a.requestAnimationFrame) globalObject.requestAnimationFrame(batchUpdate);
|
|
1037
1057
|
};
|
|
1038
1058
|
return {
|
|
1039
1059
|
useStore,
|
|
@@ -1043,21 +1063,37 @@ const useStateGlobal = (key, initialValue, options) => {
|
|
|
1043
1063
|
};
|
|
1044
1064
|
};
|
|
1045
1065
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1066
|
+
var __async = (__this, __arguments, generator) => {
|
|
1067
|
+
return new Promise((resolve, reject) => {
|
|
1068
|
+
var fulfilled = (value) => {
|
|
1069
|
+
try {
|
|
1070
|
+
step(generator.next(value));
|
|
1071
|
+
} catch (e) {
|
|
1072
|
+
reject(e);
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
var rejected = (value) => {
|
|
1076
|
+
try {
|
|
1077
|
+
step(generator.throw(value));
|
|
1078
|
+
} catch (e) {
|
|
1079
|
+
reject(e);
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
1083
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
1084
|
+
});
|
|
1060
1085
|
};
|
|
1086
|
+
const optimisticUpdate = (setState, updateFn, apiCall, rollbackFn) => __async(void 0, null, function* () {
|
|
1087
|
+
const prevState = setState.useStore();
|
|
1088
|
+
const optimisticState = updateFn(prevState);
|
|
1089
|
+
setState.set(optimisticState);
|
|
1090
|
+
try {
|
|
1091
|
+
yield apiCall();
|
|
1092
|
+
} catch (error) {
|
|
1093
|
+
console.error("API request failed:", error);
|
|
1094
|
+
setState.set(rollbackFn ? rollbackFn(prevState) : prevState);
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1061
1097
|
|
|
1062
1098
|
var __defProp = Object.defineProperty;
|
|
1063
1099
|
var __defProps = Object.defineProperties;
|
|
@@ -1081,16 +1117,26 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
|
1081
1117
|
const mergeCRDT = (localState, remoteState) => {
|
|
1082
1118
|
return __spreadProps(__spreadValues(__spreadValues({}, localState), remoteState), { lastUpdated: Date.now() });
|
|
1083
1119
|
};
|
|
1084
|
-
const syncCRDT = (
|
|
1085
|
-
const localState =
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1120
|
+
const syncCRDT = (remoteState, setState) => {
|
|
1121
|
+
const localState = setState.useStore();
|
|
1122
|
+
const mergedState = mergeCRDT(localState, remoteState);
|
|
1123
|
+
setState(mergedState);
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1126
|
+
const derivedState = (dependencies, computeFn) => {
|
|
1127
|
+
const derived = { value: computeFn(...dependencies.map((dep) => dep.useStore())) };
|
|
1128
|
+
dependencies.forEach(
|
|
1129
|
+
(dep) => dep.useStore().listeners.add(() => {
|
|
1130
|
+
derived.value = computeFn(...dependencies.map((dep2) => dep2.useStore()));
|
|
1131
|
+
})
|
|
1132
|
+
);
|
|
1133
|
+
return () => derived.value;
|
|
1088
1134
|
};
|
|
1089
1135
|
|
|
1090
|
-
exports.
|
|
1091
|
-
exports.
|
|
1092
|
-
exports.loadEncryptedState = loadEncryptedState;
|
|
1136
|
+
exports.derivedState = derivedState;
|
|
1137
|
+
exports.mergeCRDT = mergeCRDT;
|
|
1093
1138
|
exports.optimisticUpdate = optimisticUpdate;
|
|
1139
|
+
exports.restoreEncryptedState = restoreEncryptedState;
|
|
1094
1140
|
exports.restoreState = restoreState;
|
|
1095
1141
|
exports.saveEncryptedState = saveEncryptedState;
|
|
1096
1142
|
exports.saveState = saveState;
|