Skip to content

Commit 66e44b6

Browse files
committed
docs: add README to rescript-signals-react
1 parent 0febd0b commit 66e44b6

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# rescript-signals-react
2+
3+
[![npm version](https://badgen.net/npm/v/rescript-signals-react)](https://www.npmjs.com/package/rescript-signals-react)
4+
5+
React adapter for [rescript-signals](https://github.com/brnrdog/rescript-signals) using `useSyncExternalStore`. Concurrent-mode and StrictMode safe.
6+
7+
## Installation
8+
9+
```bash
10+
npm install rescript-signals-react
11+
```
12+
13+
Add it to your `rescript.json`:
14+
15+
```json
16+
{
17+
"dependencies": ["rescript-signals", "rescript-signals-react", "@rescript/react"]
18+
}
19+
```
20+
21+
## API
22+
23+
### `useSignalValue`
24+
25+
Subscribe a component to a signal and read its current value. Re-renders only when the signal changes.
26+
27+
```rescript
28+
open Signals
29+
open SignalsReact
30+
31+
let count = Signal.make(0)
32+
33+
@react.component
34+
let make = () => {
35+
let value = useSignalValue(count)
36+
<span> {React.string(Int.toString(value))} </span>
37+
}
38+
```
39+
40+
### `useSignal`
41+
42+
Create a component-local signal. Returns `(value, signal, setter)` — the signal and setter are referentially stable across re-renders.
43+
44+
```rescript
45+
open SignalsReact
46+
47+
@react.component
48+
let make = () => {
49+
let (count, _signal, setCount) = useSignal(() => 0)
50+
51+
<div>
52+
<span> {React.string(Int.toString(count))} </span>
53+
<button onClick={_ => setCount(count + 1)}>
54+
{React.string("Increment")}
55+
</button>
56+
</div>
57+
}
58+
```
59+
60+
### `useComputed`
61+
62+
Create a derived signal within a component and subscribe to it. The thunk must only depend on other signals — React values captured in the closure will go stale.
63+
64+
```rescript
65+
@react.component
66+
let make = (~a: Signal.t<int>, ~b: Signal.t<int>) => {
67+
let sum = SignalsReact.useComputed(() => Signal.get(a) + Signal.get(b))
68+
<div> {React.string(Int.toString(sum))} </div>
69+
}
70+
```
71+
72+
### `useComputedWithDeps`
73+
74+
Same as `useComputed` but rebuilds the computed when `deps` change, so React-level values can participate without going stale.
75+
76+
```rescript
77+
@react.component
78+
let make = (~signal: Signal.t<int>) => {
79+
let (multiplier, setMultiplier) = React.useState(() => 2)
80+
let result = SignalsReact.useComputedWithDeps(
81+
() => Signal.get(signal) * multiplier,
82+
multiplier,
83+
)
84+
85+
<div>
86+
<span> {React.string(Int.toString(result))} </span>
87+
<button onClick={_ => setMultiplier(prev => prev + 1)}>
88+
{React.string("Change multiplier")}
89+
</button>
90+
</div>
91+
}
92+
```
93+
94+
### `useSignalEffect`
95+
96+
Run an effect tied to the component's lifetime. The thunk executes with signal tracking enabled. Return `Some(cleanup)` to install a per-run disposer; the effect is fully disposed on unmount.
97+
98+
```rescript
99+
@react.component
100+
let make = (~signal: Signal.t<int>) => {
101+
SignalsReact.useSignalEffect(() => {
102+
Console.log2("Value changed:", Signal.get(signal))
103+
None // or Some(() => cleanup())
104+
})
105+
106+
<div />
107+
}
108+
```
109+
110+
## License
111+
112+
See [LICENSE](LICENSE) for details.

0 commit comments

Comments
 (0)