ustor 0.3.0 → 0.3.1
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 +16 -15
- package/dist/react.cjs +1 -1
- package/dist/react.es.js +1 -1
- package/package.json +1 -1
- package/types/react.d.ts +1 -16
package/README.md
CHANGED
|
@@ -473,22 +473,23 @@ npm run profile
|
|
|
473
473
|
|
|
474
474
|
## React
|
|
475
475
|
|
|
476
|
-
Install React and import the optional
|
|
476
|
+
Install React and import the optional hook:
|
|
477
477
|
|
|
478
478
|
```bash
|
|
479
479
|
npm install react
|
|
480
480
|
```
|
|
481
481
|
|
|
482
482
|
```jsx
|
|
483
|
-
import {
|
|
483
|
+
import { useSelector } from "ustor/react";
|
|
484
484
|
|
|
485
485
|
// Uses the Preact configuration from Quickstart, including api.effect.
|
|
486
486
|
const state = store({ count: 1, items: [1, 2] });
|
|
487
|
+
const selectCount = () => state.count;
|
|
487
488
|
const selectTotal = () => state.items.reduce((sum, value) => sum + value, 0);
|
|
488
489
|
|
|
489
490
|
export function Counter() {
|
|
490
|
-
const count =
|
|
491
|
-
const total =
|
|
491
|
+
const count = useSelector(selectCount);
|
|
492
|
+
const total = useSelector(selectTotal);
|
|
492
493
|
|
|
493
494
|
return (
|
|
494
495
|
<button onClick={() => { state.count++; state.items.push(state.count); }}>
|
|
@@ -498,18 +499,18 @@ export function Counter() {
|
|
|
498
499
|
}
|
|
499
500
|
```
|
|
500
501
|
|
|
501
|
-
- `
|
|
502
|
-
-
|
|
502
|
+
- `useSelector(selector)` is the single React hook for both simple properties and derived values.
|
|
503
|
+
- It tracks all compatible signal reads in the selector, including array versions.
|
|
503
504
|
- Selectors must return a primitive or stable reference, not a fresh object on every read.
|
|
504
505
|
- Keep selector functions stable with `useCallback` when they are created inside a component.
|
|
505
506
|
- React is an optional peer dependency and is excluded from the core bundle.
|
|
506
507
|
- StrictMode and unmount cleanup are tested.
|
|
507
508
|
|
|
508
|
-
Plain property reads do not schedule React renders by themselves; use the
|
|
509
|
+
Plain property reads do not schedule React renders by themselves; use the hook or another React binding.
|
|
509
510
|
|
|
510
511
|
## SSR and Next.js
|
|
511
512
|
|
|
512
|
-
Yes. `
|
|
513
|
+
Yes. `useSelector` provides a server snapshot through `useSyncExternalStore`. Server rendering creates no effects; subscriptions start on the client.
|
|
513
514
|
|
|
514
515
|
The test suite verifies:
|
|
515
516
|
|
|
@@ -520,14 +521,14 @@ The test suite verifies:
|
|
|
520
521
|
|
|
521
522
|
### Next.js App Router example
|
|
522
523
|
|
|
523
|
-
Use the
|
|
524
|
+
Use the hook in a **Client Component**. Create request- or component-owned state instead of exporting a request-specific singleton.
|
|
524
525
|
|
|
525
526
|
```jsx
|
|
526
527
|
"use client";
|
|
527
528
|
|
|
528
529
|
import { useCallback, useState } from "react";
|
|
529
530
|
import { store } from "ustor";
|
|
530
|
-
import {
|
|
531
|
+
import { useSelector } from "ustor/react";
|
|
531
532
|
// Import your shared adapter configuration once:
|
|
532
533
|
// import "@/lib/ustor-setup";
|
|
533
534
|
|
|
@@ -536,12 +537,13 @@ export default function Counter({ initialCount }) {
|
|
|
536
537
|
count: initialCount,
|
|
537
538
|
items: [1, 2],
|
|
538
539
|
}));
|
|
540
|
+
const selectCount = useCallback(() => state.count, [state]);
|
|
539
541
|
const selectTotal = useCallback(
|
|
540
542
|
() => state.items.reduce((sum, value) => sum + value, 0),
|
|
541
543
|
[state],
|
|
542
544
|
);
|
|
543
|
-
const count =
|
|
544
|
-
const total =
|
|
545
|
+
const count = useSelector(selectCount);
|
|
546
|
+
const total = useSelector(selectTotal);
|
|
545
547
|
|
|
546
548
|
return (
|
|
547
549
|
<button onClick={() => { state.count++; state.items.push(1); }}>
|
|
@@ -577,7 +579,7 @@ Declarations are included for both entry points; no separate `@types/ustor` pack
|
|
|
577
579
|
|
|
578
580
|
```typescript
|
|
579
581
|
import { store } from "ustor";
|
|
580
|
-
import {
|
|
582
|
+
import { useSelector } from "ustor/react";
|
|
581
583
|
|
|
582
584
|
const state = store({
|
|
583
585
|
count: 1,
|
|
@@ -591,14 +593,13 @@ state.count = 2; // valid
|
|
|
591
593
|
|
|
592
594
|
const doubled: number = state.double;
|
|
593
595
|
const text: string = state.nested.text;
|
|
594
|
-
const total =
|
|
596
|
+
const total = useSelector(() => state.list.reduce((sum, value) => sum + value, 0));
|
|
595
597
|
```
|
|
596
598
|
|
|
597
599
|
Exported type utilities:
|
|
598
600
|
|
|
599
601
|
- `SignalApi<Signal, Computed>` for custom adapters.
|
|
600
602
|
- `Store<T>` for reactive store inference.
|
|
601
|
-
- `SignalValue<Signal>` for React signal-value inference.
|
|
602
603
|
|
|
603
604
|
Run the repository's strict compile-time tests with:
|
|
604
605
|
|
package/dist/react.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("react");const r={}
|
|
1
|
+
"use strict";var e=require("react");const r={};exports.useSelector=t=>{const c=e.useCallback(e=>{if(!r.effect)throw new Error("ustor/react: configure api.effect with cleanup support");let c=!0;return r.effect(()=>{t(),c?c=!1:e()})},[t]);return e.useSyncExternalStore(c,t,t)};
|
package/dist/react.es.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useCallback as
|
|
1
|
+
import{useCallback as r,useSyncExternalStore as t}from"react";const e={},o=o=>{const c=r(r=>{if(!e.effect)throw new Error("ustor/react: configure api.effect with cleanup support");let t=!0;return e.effect(()=>{o(),t?t=!1:r()})},[o]);return t(c,o,o)};export{o as useSelector};
|
package/package.json
CHANGED
package/types/react.d.ts
CHANGED
|
@@ -1,17 +1,2 @@
|
|
|
1
|
-
export type SignalValue<Signal> = Signal extends { state: readonly (infer Value)[] }
|
|
2
|
-
? Value
|
|
3
|
-
: Signal extends { value: infer Value }
|
|
4
|
-
? Value
|
|
5
|
-
: Signal extends { get(): infer Value }
|
|
6
|
-
? Value
|
|
7
|
-
: Signal extends () => infer Value
|
|
8
|
-
? Value
|
|
9
|
-
: Signal extends readonly [() => infer Value, ...any[]]
|
|
10
|
-
? Value
|
|
11
|
-
: unknown;
|
|
12
|
-
|
|
13
1
|
/** Subscribe to a selector that returns a primitive or stable reference. */
|
|
14
|
-
export declare function
|
|
15
|
-
|
|
16
|
-
/** Subscribe to one underlying signal exposed as state.$property. */
|
|
17
|
-
export declare function useSignal<Signal>(signal: Signal): SignalValue<Signal>;
|
|
2
|
+
export declare function useSelector<Value>(selector: () => Value): Value;
|