@manyducks.co/dolla 2.0.0 → 3.1.0
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 +133 -284
- package/dist/context-B5blupD2.js +363 -0
- package/dist/context-B5blupD2.js.map +1 -0
- package/dist/core/context.d.ts +29 -144
- package/dist/core/debug.d.ts +19 -0
- package/dist/core/index.d.ts +15 -16
- package/dist/core/markup/helpers.d.ts +34 -0
- package/dist/core/markup/html.d.ts +3 -0
- package/dist/core/{nodes → markup/nodes}/dom.d.ts +5 -4
- package/dist/core/markup/nodes/dynamic.d.ts +16 -0
- package/dist/core/markup/nodes/element.d.ts +14 -0
- package/dist/core/markup/nodes/portal.d.ts +15 -0
- package/dist/core/markup/nodes/repeat.d.ts +21 -0
- package/dist/core/markup/nodes/view.d.ts +17 -0
- package/dist/core/markup/scheduler.d.ts +1 -0
- package/dist/core/markup/types.d.ts +62 -0
- package/dist/core/markup/utils.d.ts +22 -0
- package/dist/core/ref.d.ts +6 -12
- package/dist/core/root.d.ts +36 -0
- package/dist/core/signals.d.ts +46 -76
- package/dist/core/symbols.d.ts +2 -0
- package/dist/core-JHktdqjt.js +242 -0
- package/dist/core-JHktdqjt.js.map +1 -0
- package/dist/http/index.d.ts +21 -33
- package/dist/http.js +89 -149
- package/dist/http.js.map +1 -1
- package/dist/index.js +4 -174
- package/dist/jsx-dev-runtime.d.ts +4 -3
- package/dist/jsx-dev-runtime.js +12 -9
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +5 -4
- package/dist/jsx-runtime.js +17 -12
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/router/index.d.ts +4 -3
- package/dist/router/router.d.ts +19 -162
- package/dist/router/store.d.ts +12 -0
- package/dist/router/types.d.ts +152 -0
- package/dist/router/utils.d.ts +99 -0
- package/dist/router/utils.test.d.ts +1 -0
- package/dist/router.js +428 -5
- package/dist/router.js.map +1 -1
- package/dist/signals-CMJPGr_M.js +354 -0
- package/dist/signals-CMJPGr_M.js.map +1 -0
- package/dist/translate/index.d.ts +82 -0
- package/dist/translate.js +125 -0
- package/dist/translate.js.map +1 -0
- package/dist/types.d.ts +21 -39
- package/dist/utils.d.ts +41 -29
- package/dist/utils.test.d.ts +1 -0
- package/dist/virtual/index.d.ts +1 -0
- package/dist/virtual/list.d.ts +53 -0
- package/package.json +19 -16
- package/dist/core/app.d.ts +0 -24
- package/dist/core/env.d.ts +0 -3
- package/dist/core/hooks.d.ts +0 -70
- package/dist/core/logger.d.ts +0 -42
- package/dist/core/logger.test.d.ts +0 -0
- package/dist/core/markup.d.ts +0 -82
- package/dist/core/markup.test.d.ts +0 -0
- package/dist/core/nodes/_markup.d.ts +0 -36
- package/dist/core/nodes/dynamic.d.ts +0 -22
- package/dist/core/nodes/element.d.ts +0 -27
- package/dist/core/nodes/portal.d.ts +0 -18
- package/dist/core/nodes/repeat.d.ts +0 -27
- package/dist/core/nodes/view.d.ts +0 -25
- package/dist/core/views/default-crash-view.d.ts +0 -25
- package/dist/core/views/for.d.ts +0 -21
- package/dist/core/views/fragment.d.ts +0 -7
- package/dist/core/views/portal.d.ts +0 -16
- package/dist/core/views/show.d.ts +0 -25
- package/dist/fragment-BahD_BJA.js +0 -7
- package/dist/fragment-BahD_BJA.js.map +0 -1
- package/dist/i18n/index.d.ts +0 -134
- package/dist/i18n.js +0 -309
- package/dist/i18n.js.map +0 -1
- package/dist/index-DRJlxs-Q.js +0 -535
- package/dist/index-DRJlxs-Q.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger-Aqi9m1CF.js +0 -565
- package/dist/logger-Aqi9m1CF.js.map +0 -1
- package/dist/markup-8jNhoqDe.js +0 -1089
- package/dist/markup-8jNhoqDe.js.map +0 -1
- package/dist/router/hooks.d.ts +0 -2
- package/dist/router/router.utils.d.ts +0 -93
- package/dist/typeChecking-5kmX0ulW.js +0 -65
- package/dist/typeChecking-5kmX0ulW.js.map +0 -1
- package/dist/typeChecking.d.ts +0 -95
- package/docs/buildless.md +0 -132
- package/docs/components.md +0 -238
- package/docs/hooks.md +0 -356
- package/docs/http.md +0 -178
- package/docs/i18n.md +0 -220
- package/docs/index.md +0 -10
- package/docs/markup.md +0 -136
- package/docs/mixins.md +0 -176
- package/docs/ref.md +0 -77
- package/docs/router.md +0 -281
- package/docs/setup.md +0 -137
- package/docs/signals.md +0 -262
- package/docs/stores.md +0 -113
- package/docs/views.md +0 -356
- package/notes/atomic.md +0 -452
- package/notes/elimination.md +0 -33
- package/notes/observable.md +0 -180
- package/notes/scratch.md +0 -565
- package/notes/splitting.md +0 -5
- package/notes/views.md +0 -195
- package/vite.config.js +0 -22
- /package/dist/core/{hooks.test.d.ts → markup/html.test.d.ts} +0 -0
- /package/dist/core/{ref.test.d.ts → markup/utils.test.d.ts} +0 -0
- /package/dist/router/{router.utils.test.d.ts → matcher.test.d.ts} +0 -0
- /package/dist/{typeChecking.test.d.ts → router/router.test.d.ts} +0 -0
package/docs/signals.md
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
# ⚡ Dolla Signals: The Main Vibe
|
|
2
|
-
|
|
3
|
-
Wanna know how Dolla works? It's all about **Signals**. Fr, they're the most important thing to get. They're like little magic boxes that hold your data, and they're the reason Dolla is so fast and reactive without all the drama of other frameworks.
|
|
4
|
-
|
|
5
|
-
## So, what even IS a Signal?
|
|
6
|
-
|
|
7
|
-
A signal is just a little box that holds a value. That's it. But it's a special box.
|
|
8
|
-
|
|
9
|
-
- When you **read** from the box (get its value), it takes notes on who's asking.
|
|
10
|
-
- When you **write** to the box (change its value), it automatically tells everyone who was asking, "yo, I changed\!"
|
|
11
|
-
|
|
12
|
-
This is the core of Dolla's reactivity. It's a system of "subscribers" and "publishers." When a signal changes, it publishes an update, and only the exact parts of your app that subscribed to that signal will react. No wasted effort.
|
|
13
|
-
|
|
14
|
-
This is why Dolla doesn't need a Virtual DOM. It doesn't have to guess what changed; the signals tell it _exactly_ what changed and where.
|
|
15
|
-
|
|
16
|
-
## Making Signals in Components: `useSignal`
|
|
17
|
-
|
|
18
|
-
The main way you'll make a signal _inside a component_ is with the `useSignal` hook. It gives you back a pair of things in an array, just like React's `useState`.
|
|
19
|
-
|
|
20
|
-
```jsx
|
|
21
|
-
import { useSignal } from "@manyducks.co/dolla";
|
|
22
|
-
|
|
23
|
-
function MyComponent() {
|
|
24
|
-
// [getter, setter]
|
|
25
|
-
const [$count, setCount] = useSignal(0);
|
|
26
|
-
// ...
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
- `$count`: This is the **getter**. It's a function that you call to get the signal's current value. We use a `$` at the start by convention to make signals easy to spot.
|
|
31
|
-
- `setCount`: This is the **setter**. It's a function you call to update the signal's value.
|
|
32
|
-
|
|
33
|
-
### Reading and Writing
|
|
34
|
-
|
|
35
|
-
Here's the flow:
|
|
36
|
-
|
|
37
|
-
```jsx
|
|
38
|
-
const [$count, setCount] = useSignal(0);
|
|
39
|
-
|
|
40
|
-
// To READ the value in your JS, call the getter function:
|
|
41
|
-
console.log($count()); // -> 0
|
|
42
|
-
|
|
43
|
-
// To WRITE a new value, call the setter:
|
|
44
|
-
setCount(1);
|
|
45
|
-
console.log($count()); // -> 1
|
|
46
|
-
|
|
47
|
-
// The setter can also take a function, just like in React:
|
|
48
|
-
setCount((currentCount) => currentCount + 1);
|
|
49
|
-
console.log($count()); // -> 2
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Super Important Rule:** In your JSX, you can usually just drop the signal right in (`<p>{$count}</p>`). Dolla is smart enough to know it needs to read the value there. But in your JavaScript code (like in an `useEffect` or an event handler), you **must** call it like a function to get the value (`$count()`).
|
|
53
|
-
|
|
54
|
-
## Derived Signals: `useMemo`
|
|
55
|
-
|
|
56
|
-
Sometimes you have state that depends on _other_ state. For example, a `fullName` that's made from a `firstName` and a `lastName`. You don't want to have to manually update `fullName` every time one of the other two changes. That's a job for `useMemo`.
|
|
57
|
-
|
|
58
|
-
`useMemo` creates a new, read-only signal that automatically updates when its dependencies change.
|
|
59
|
-
|
|
60
|
-
```jsx
|
|
61
|
-
import { useSignal, useMemo } from "@manyducks.co/dolla";
|
|
62
|
-
|
|
63
|
-
function Greeter() {
|
|
64
|
-
const [$firstName, setFirstName] = useSignal("John");
|
|
65
|
-
const [$lastName, setLastName] = useSignal("Doe");
|
|
66
|
-
|
|
67
|
-
// This is a derived signal. It's subscribed to $firstName and $lastName.
|
|
68
|
-
const $fullName = useMemo(() => {
|
|
69
|
-
console.log("Recalculating full name...");
|
|
70
|
-
return `${$firstName()} ${$lastName()}`;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<div>
|
|
75
|
-
<p>Full Name: {$fullName}</p>
|
|
76
|
-
<input value={$firstName} onInput={(e) => setFirstName(e.target.value)} />
|
|
77
|
-
<input value={$lastName} onInput={(e) => setLastName(e.target.value)} />
|
|
78
|
-
</div>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
In this example, the "Recalculating..." message will only log when you type in one of the input boxes. If you just click around, the memo doesn't re-run because its dependencies (`$firstName` and `$lastName`) haven't changed. It's super efficient.
|
|
84
|
-
|
|
85
|
-
## Automatic Tracking: The Real Magic
|
|
86
|
-
|
|
87
|
-
This is the part that makes Dolla so chill to work with. When you use a signal inside a `useMemo` or a `useEffect`, Dolla automatically figures out that the effect/memo depends on that signal. You don't have to tell it.
|
|
88
|
-
|
|
89
|
-
```jsx
|
|
90
|
-
const [$count, setCount] = useSignal(0);
|
|
91
|
-
const [$name, setName] = useSignal("User");
|
|
92
|
-
|
|
93
|
-
// This effect uses both $count and $name
|
|
94
|
-
useEffect(() => {
|
|
95
|
-
console.log(`The count is ${$count()} for user ${$name()}`);
|
|
96
|
-
});
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
In this example, Dolla knows that this `useEffect` is subscribed to **both** `$count` and `$name`. If you call `setCount(1)`, the effect will re-run. If you call `setName("Alice")`, the effect will also re-run. You don't have to manage a dependency array like in React. It just works.
|
|
100
|
-
|
|
101
|
-
## Grouping Updates: `batch`
|
|
102
|
-
|
|
103
|
-
Imagine you need to update a bunch of signals all at once.
|
|
104
|
-
|
|
105
|
-
```jsx
|
|
106
|
-
setFirstName("Jane");
|
|
107
|
-
setLastName("Smith");
|
|
108
|
-
setAge(30);
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
If you do this, you might cause three separate updates, and any effects that depend on these signals might run three times. That's not ideal.
|
|
112
|
-
|
|
113
|
-
The `batch` function lets you group all these updates together. Dolla will perform all the changes, and then at the very end, it will run all the necessary effects just a single time.
|
|
114
|
-
|
|
115
|
-
```jsx
|
|
116
|
-
import { batch } from "@manyducks.co/dolla";
|
|
117
|
-
|
|
118
|
-
const updateUser = () => {
|
|
119
|
-
batch(() => {
|
|
120
|
-
setFirstName("Jane");
|
|
121
|
-
setLastName("Smith");
|
|
122
|
-
setAge(30);
|
|
123
|
-
});
|
|
124
|
-
// Now, any effects that depend on these three signals will only run once!
|
|
125
|
-
};
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
It's a great tool for keeping your app snappy when you have complex state changes.
|
|
129
|
-
|
|
130
|
-
## Standalone Signals: Going Hookless
|
|
131
|
-
|
|
132
|
-
Okay, so all the hooks like `useSignal` and `useMemo` are great, but they have one rule: you can only use them inside a component (a View, Store, or Mixin). But what if you need reactivity _outside_ of a component?
|
|
133
|
-
|
|
134
|
-
Maybe you wanna make a global store in its own file, or you're just messing around in a plain `.js` file. That's where the standalone signal functions come in. They're the same core magic, just without the "use" prefix.
|
|
135
|
-
|
|
136
|
-
### `signal(initialValue?)`
|
|
137
|
-
|
|
138
|
-
This is the hookless version of `useSignal`. It does the exact same thing: creates a reactive box and gives you a `[getter, setter]` pair.
|
|
139
|
-
|
|
140
|
-
```jsx
|
|
141
|
-
import { signal, effect } from "@manyducks.co/dolla";
|
|
142
|
-
|
|
143
|
-
// We're not in a component, just a regular JS file!
|
|
144
|
-
const [$time, setTime] = signal(new Date());
|
|
145
|
-
|
|
146
|
-
// We can use the standalone `effect` to watch it.
|
|
147
|
-
effect(() => {
|
|
148
|
-
console.log("The time is now:", $time());
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
setInterval(() => {
|
|
152
|
-
setTime(new Date());
|
|
153
|
-
}, 1000);
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### `writable(initialValue?)`
|
|
157
|
-
|
|
158
|
-
This is another way to make a signal. Instead of a `[getter, setter]` pair, it gives you back a single function that's both a getter _and_ has a `.set()` method. It's just a different flavor, sometimes it's cleaner.
|
|
159
|
-
|
|
160
|
-
```jsx
|
|
161
|
-
import { writable } from "@manyducks.co/dolla";
|
|
162
|
-
|
|
163
|
-
const $name = writable("Guest");
|
|
164
|
-
|
|
165
|
-
console.log($name()); // -> "Guest"
|
|
166
|
-
|
|
167
|
-
$name.set("Alice");
|
|
168
|
-
console.log($name()); // -> "Alice"
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### `memo(compute)`
|
|
172
|
-
|
|
173
|
-
The hookless version of `useMemo`. It takes a function and gives you back a new, read-only signal that updates when its dependencies do.
|
|
174
|
-
|
|
175
|
-
```jsx
|
|
176
|
-
import { signal, memo } from "@manyducks.co/dolla";
|
|
177
|
-
|
|
178
|
-
const [$firstName, setFirstName] = signal("John");
|
|
179
|
-
const [$lastName, setLastName] = signal("Doe");
|
|
180
|
-
|
|
181
|
-
const $fullName = memo(() => `${$firstName()} ${$lastName()}`);
|
|
182
|
-
|
|
183
|
-
console.log($fullName()); // -> "John Doe"
|
|
184
|
-
setFirstName("Jane");
|
|
185
|
-
console.log($fullName()); // -> "Jane Doe"
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### `effect(callback)`
|
|
189
|
-
|
|
190
|
-
The hookless version of `useEffect`. It runs your callback once, tracks any signals you use inside it, and then re-runs the callback whenever those signals change.
|
|
191
|
-
|
|
192
|
-
**Super Important Rule:** The standalone `effect` function returns an `unsubscribe` function. If you're using `effect` outside of a component, you're responsible for calling this cleanup function yourself to prevent memory leaks\! (The `useEffect` hook does this for you automatically when the component unmounts).
|
|
193
|
-
|
|
194
|
-
```jsx
|
|
195
|
-
import { signal, effect } from "@manyducks.co/dolla";
|
|
196
|
-
|
|
197
|
-
const [$count, setCount] = signal(0);
|
|
198
|
-
|
|
199
|
-
const unsubscribe = effect(() => {
|
|
200
|
-
console.log("Count changed:", $count());
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
setCount(1); // logs "Count changed: 1"
|
|
204
|
-
|
|
205
|
-
// Later, when you're done...
|
|
206
|
-
unsubscribe();
|
|
207
|
-
setCount(2); // Nothing logs, because we unsubscribed.
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Utility Functions: The Nitty Gritty
|
|
211
|
-
|
|
212
|
-
These are some super useful functions for working with signals.
|
|
213
|
-
|
|
214
|
-
- **`get(value)`:** This function "unwraps" a value. If you give it a signal, it gives you the value inside. If you give it a plain value, it just gives it right back. **Crucially, if you're inside a reactive scope like `useEffect`, `get` will track the signal as a dependency.**
|
|
215
|
-
- **`untracked(fn)`:** This function also "unwraps" a value from a signal, but it does it in "stealth mode." It tells Dolla, "hey, get me this value, but don't make me a subscriber." **It's the equivalent of `get`, but it explicitly opts out of tracking.**
|
|
216
|
-
|
|
217
|
-
Here's the difference in action:
|
|
218
|
-
|
|
219
|
-
```jsx
|
|
220
|
-
import { get, untracked, signal, effect } from "@manyducks.co/dolla";
|
|
221
|
-
|
|
222
|
-
const [$count, setCount] = signal(0);
|
|
223
|
-
const [$name, setName] = signal("User");
|
|
224
|
-
|
|
225
|
-
effect(() => {
|
|
226
|
-
// We're using `get`, so this effect is now subscribed to $count.
|
|
227
|
-
console.log(`Count changed: ${get($count)}`);
|
|
228
|
-
|
|
229
|
-
// We're using `untracked`, so this effect is NOT subscribed to $name.
|
|
230
|
-
const name = untracked(() => $name());
|
|
231
|
-
console.log(`(The user is currently ${name})`);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// This will trigger the effect to re-run.
|
|
235
|
-
setCount(1);
|
|
236
|
-
|
|
237
|
-
// This will NOT trigger the effect.
|
|
238
|
-
setName("Alice");
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
- **`readable(value)`:** This does the opposite of `get`. It "wraps" a value, making sure you always have a signal to work with. If you give it a signal, it just returns it. If you give it a plain value, it creates a new read-only signal with that value. This is great for writing flexible functions that can accept either a signal or a plain value as an input.
|
|
242
|
-
|
|
243
|
-
```jsx
|
|
244
|
-
import { readable, signal } from "@manyducks.co/dolla";
|
|
245
|
-
|
|
246
|
-
// Give it a plain value, get a signal back.
|
|
247
|
-
const $name = readable("Alice");
|
|
248
|
-
console.log($name()); // -> "Alice"
|
|
249
|
-
|
|
250
|
-
// Give it an existing signal, get the same signal back.
|
|
251
|
-
const [$count, setCount] = signal(10);
|
|
252
|
-
const $readableCount = readable($count);
|
|
253
|
-
console.log($readableCount === $count); // -> true
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
---
|
|
257
|
-
|
|
258
|
-
End.
|
|
259
|
-
|
|
260
|
-
- [🗂️ Docs](./index.md)
|
|
261
|
-
- [🏠 README](../README.md)
|
|
262
|
-
- [🦆 That's a lot of ducks.](https://www.manyducks.co)
|
package/docs/stores.md
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# Dolla Stores: The State Management Glow Up
|
|
2
|
-
|
|
3
|
-
Aight, let's get into one of the most clutch features in Dolla: **Stores**. If you've ever built an app that's more than just a single page, you've probably run into the nightmare of trying to share state between components that are far apart. This is called "prop drilling," and it's a total vibe killer.
|
|
4
|
-
|
|
5
|
-
Prop drilling is when you have to pass a prop down through like, five different components that don't even need it, just to get it to the one component at the bottom that _actually_ needs it. It's messy, it's annoying, and it makes your code a nightmare to change later.
|
|
6
|
-
|
|
7
|
-
**Stores are the answer.** They're Dolla's built-in way to create shared state that any component can tap into, no matter where it is in your app. No more prop drilling. Ever.
|
|
8
|
-
|
|
9
|
-
## So, what even IS a Store?
|
|
10
|
-
|
|
11
|
-
A Store is just a special type of component that doesn't render any UI. Its only job is to hold onto some state (signals) and the functions that can change that state. It's like a little brain for a specific part of your app.
|
|
12
|
-
|
|
13
|
-
By creating a store, you're making a clean, reusable API for your state that any component can use.
|
|
14
|
-
|
|
15
|
-
## How to Make a Store
|
|
16
|
-
|
|
17
|
-
Making a store is super easy. It's just a function that returns an object. Inside, you use `useSignal`, `useMemo`, and other hooks to create your state, and then you return the signals and functions you want other components to be able to use.
|
|
18
|
-
|
|
19
|
-
### Example: A `ThemeStore`
|
|
20
|
-
|
|
21
|
-
Let's make a simple store that keeps track of whether the app is in light or dark mode.
|
|
22
|
-
|
|
23
|
-
```jsx
|
|
24
|
-
import { useSignal, useMemo } from "@manyducks.co/dolla";
|
|
25
|
-
|
|
26
|
-
// This is our store! It's just a function.
|
|
27
|
-
function ThemeStore(options) {
|
|
28
|
-
// 1. Create the state with useSignal. We can use the options to set a default.
|
|
29
|
-
const [$theme, setTheme] = useSignal(options.defaultTheme || "light");
|
|
30
|
-
|
|
31
|
-
// 2. We can even have derived state with useMemo.
|
|
32
|
-
const $isDarkMode = useMemo(() => $theme() === "dark");
|
|
33
|
-
|
|
34
|
-
// 3. Create functions that are the ONLY way to change the state.
|
|
35
|
-
const toggleTheme = () => {
|
|
36
|
-
setTheme((currentTheme) => (currentTheme === "light" ? "dark" : "light"));
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// 4. Return the public API for our store.
|
|
40
|
-
return { $theme, $isDarkMode, toggleTheme };
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
By only returning `toggleTheme`, we're making sure no component can just set the theme to some random value like `"bunnies"`. They _have_ to use our function. It keeps things clean and predictable.
|
|
45
|
-
|
|
46
|
-
## How to Use a Store
|
|
47
|
-
|
|
48
|
-
Using a store is a two-step process: you **provide** it, and then you **use** it.
|
|
49
|
-
|
|
50
|
-
### Step 1: `useStoreProvider`
|
|
51
|
-
|
|
52
|
-
First, you need to make your store available to a part of your app. You usually do this in a high-level component, like your main `App` view. This is called "providing" the store.
|
|
53
|
-
|
|
54
|
-
```jsx
|
|
55
|
-
import { useStoreProvider } from "@manyducks.co/dolla";
|
|
56
|
-
import { ThemeStore } from "./stores/ThemeStore.js";
|
|
57
|
-
import { PageContent } from "./PageContent.jsx";
|
|
58
|
-
|
|
59
|
-
function App() {
|
|
60
|
-
// We're providing the ThemeStore to our entire app.
|
|
61
|
-
// We can also pass in options here.
|
|
62
|
-
useStoreProvider(ThemeStore, { defaultTheme: "dark" });
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<div>
|
|
66
|
-
<h1>My Awesome App</h1>
|
|
67
|
-
<PageContent />
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Now, the `App` component and every single component inside of it (no matter how deep) can access this one instance of `ThemeStore`.
|
|
74
|
-
|
|
75
|
-
### Step 2: `useStore`
|
|
76
|
-
|
|
77
|
-
Now that the store is provided, any child component can just ask for it with the `useStore` hook.
|
|
78
|
-
|
|
79
|
-
```jsx
|
|
80
|
-
import { useStore } from "@manyducks.co/dolla";
|
|
81
|
-
import { ThemeStore } from "./stores/ThemeStore.js";
|
|
82
|
-
|
|
83
|
-
function ThemeToggleButton() {
|
|
84
|
-
// Just ask for the ThemeStore! Dolla will find it.
|
|
85
|
-
const theme = useStore(ThemeStore);
|
|
86
|
-
|
|
87
|
-
return <button onClick={theme.toggleTheme}>Switch to {() => (theme.$isDarkMode() ? "Light" : "Dark")} Mode</button>;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function Header() {
|
|
91
|
-
const theme = useStore(ThemeStore);
|
|
92
|
-
|
|
93
|
-
// This class will automatically update when the theme changes!
|
|
94
|
-
return (
|
|
95
|
-
<header class={{ "dark-mode": theme.$isDarkMode }}>
|
|
96
|
-
<h2>Current Theme: {theme.$theme}</h2>
|
|
97
|
-
<ThemeToggleButton />
|
|
98
|
-
</header>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
And that's it\! The `ThemeToggleButton` and `Header` can be anywhere inside `App`, and they'll both get the exact same store instance. When you click the button, `toggleTheme` is called, the `$theme` signal updates, and both the button text and the header's class will automatically change.
|
|
104
|
-
|
|
105
|
-
No prop drilling. Just clean, reactive state. It's a whole vibe.
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
End.
|
|
110
|
-
|
|
111
|
-
- [🗂️ Docs](./index.md)
|
|
112
|
-
- [🏠 README](../README.md)
|
|
113
|
-
- [🦆 That's a lot of ducks.](https://www.manyducks.co)
|