Skip to content

Commit 1b478d5

Browse files
committed
docs(changeset): Improve type inference and documentation.
1 parent 32834b3 commit 1b478d5

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

.changeset/gold-moons-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"kosha": patch
3+
---
4+
5+
Improve type inference and documentation.

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ Yes. Middleware support is built-in. A working persist middleware is included. Y
189189

190190
While `Date` serializes fine, **avoid storing `Set` or `Map`** directly in global state, since Kosha uses `JSON.stringify` to diff selector outputs. Use arrays or plain objects instead for best results.
191191

192+
### 5. Isnt JSON.stringify unreliable because key order might change?
193+
194+
Noin Kosha, youre comparing outputs of the same selector function across renders. Since the order of keys in JavaScript objects is preserved in deterministic function outputs, JSON.stringify remains stable and reliable in this context.
195+
192196
---
193197

194198
## 🚧 Known Limitations
@@ -234,6 +238,24 @@ Got an idea for a middleware plugin or improvement? We'd love to collaborate.
234238
235239
---
236240
241+
## 🧠 Internals & Caveats
242+
243+
### 🔍 Why use `JSON.stringify` for selector comparison?
244+
245+
Kosha compares previous and next selector outputs using `JSON.stringify` to prevent unnecessary re-renders. This approach has several benefits:
246+
247+
- It's **fast** and works for most serializable primitives and plain objects.
248+
- It ensures **deep comparison** out-of-the-box without manual equality functions.
249+
250+
### ⚠️ What about key order in objects?
251+
252+
This is a common concern, but not an issue in Kosha:
253+
254+
> Kosha always compares results of the **same selector function**, so the key order is preserved unless your selector behaves non-deterministically (e.g., relies on `Object.keys()` or mutation).
255+
> As long as your selector returns a consistent structure, `JSON.stringify` comparison will be reliable.
256+
257+
---
258+
237259
## 📜 License
238260
239261
Kosha is licensed under the **MPL-2.0** license.

lib/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ export type StoreCreator<T extends BaseType> = (
2121

2222
export type Middleware<T extends BaseType> = (storeCreator: StoreCreator<T>) => StoreCreator<T>;
2323

24-
export const create = <T extends BaseType>(storeCreator: StoreCreator<T>) => {
24+
export const create: <T extends BaseType>(
25+
storeCreator: StoreCreator<T>,
26+
) => {
27+
(): T;
28+
<U>(selectorFunc: (state: T) => U): U;
29+
getState: () => T | null;
30+
} = <T extends BaseType>(storeCreator: StoreCreator<T>) => {
2531
const listeners = new Set<ListenerWithSelector<T, unknown>>();
2632
const stateRef: { k: T | null } = { k: null };
2733
let get = () => stateRef.k;
@@ -45,13 +51,13 @@ export const create = <T extends BaseType>(storeCreator: StoreCreator<T>) => {
4551
stateRef.k = rest;
4652
get = __get ?? get;
4753

54+
const map = new Map<(state: T) => unknown, unknown>();
4855
/**
4956
* A React hook to access the store's state or derived slices of it.
5057
* @param {(state: T) => U} [selectorFunc]
5158
* A function to extract a slice of the state for optimization.
5259
* @returns {U | T} The selected slice or the entire state.
5360
*/
54-
const map = new Map<(state: T) => unknown, unknown>();
5561
const useHook = <U = T>(selectorFunc?: (state: T) => U): U => {
5662
const getSlice = () => {
5763
const newValue = selectorFunc!(get()!);

packages/shared/src/client/demo/basic-example/counter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const useKosha = create<CounterStore>(set => ({
1212

1313
/** Counter Controller */
1414
export const CounterController = () => {
15-
const { count, setCount } = useKosha();
15+
const [count, setCount] = useKosha(({ count, setCount }) => [count, setCount]);
1616
return <input type="number" value={count} onChange={e => setCount(Number(e.target.value))} />;
1717
};
1818

0 commit comments

Comments
 (0)