nanoeffects 0.19.1 → 0.20.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.
Files changed (46) hide show
  1. package/dist/{action-creator-HFA_LZOH.d.ts → action-creator-Bpa8BUS9.d.ts} +18 -7
  2. package/dist/actions.d.ts +3 -3
  3. package/dist/actions.js +1 -1
  4. package/dist/{context-types-BNcs43eY.d.ts → context-types-BKIH5a8s.d.ts} +1 -1
  5. package/dist/context.d.ts +2 -2
  6. package/dist/dev.d.ts +2 -2
  7. package/dist/dev.js +1 -1
  8. package/dist/effects.d.ts +4 -8
  9. package/dist/index.d.ts +2 -2
  10. package/dist/match.d.ts +1 -1
  11. package/dist/{module-DTf73Wdq.d.ts → module-B0KVDNjY.d.ts} +14 -9
  12. package/dist/mount-each-D54UqAhZ.js +1 -0
  13. package/dist/notrace/{action-creator-CbFf398i.d.ts → action-creator-D2CotugT.d.ts} +16 -7
  14. package/dist/notrace/actions.d.ts +14 -9
  15. package/dist/notrace/actions.js +1 -1
  16. package/dist/notrace/effects.d.ts +4 -8
  17. package/dist/notrace/index.d.ts +2 -2
  18. package/dist/notrace/{plugin-C5vIjxhR.d.ts → plugin-C6KA4dX-.d.ts} +1 -1
  19. package/dist/notrace/policies.d.ts +1 -1
  20. package/dist/notrace/redux.d.ts +1 -1
  21. package/dist/observable.d.ts +1 -1
  22. package/dist/oop.d.ts +1 -1
  23. package/dist/{plugin-Sy8z9IId.d.ts → plugin-D9UTzGRG.d.ts} +2 -2
  24. package/dist/policies.d.ts +2 -2
  25. package/dist/react.d.ts +3 -4
  26. package/dist/redux.d.ts +1 -1
  27. package/dist/scope.d.ts +4 -4
  28. package/dist/signal.d.ts +1 -1
  29. package/dist/state-of-C19H6BoV.d.ts +10 -0
  30. package/dist/trace.d.ts +1 -1
  31. package/dist/{types-DaZT158m.d.ts → types-CbdJKC2z.d.ts} +2 -2
  32. package/dist/vue.d.ts +72 -0
  33. package/dist/vue.js +1 -0
  34. package/dist/{with-policy-C_mX7S54.d.ts → with-policy-BeH8wCkX.d.ts} +1 -1
  35. package/docs/README.md +2 -0
  36. package/docs/actions.md +31 -1
  37. package/docs/chat-example.md +241 -0
  38. package/docs/migrating-from-rxjs.md +58 -1
  39. package/docs/package.md +1 -0
  40. package/docs/plugins.md +3 -3
  41. package/docs/starter.md +14 -1
  42. package/docs/typescript.md +14 -0
  43. package/docs/vue.md +96 -0
  44. package/llms-full.txt +467 -7
  45. package/llms.txt +4 -2
  46. package/package.json +23 -3
package/docs/vue.md ADDED
@@ -0,0 +1,96 @@
1
+ # Use nanoeffects in a Vue app
2
+
3
+ Use this page when your app is in Vue 3 and a component has to talk to the bus: tell it that a value changed, and show the result of an event. `vuePlugin` gives you two functions for that. To see them in a running project, start from the `vue-ts` template in [Start a project from a template](starter.md#start-with-vue).
4
+
5
+ You need Vue 3.3 or newer and `nanoeffects` installed. If you do not know what the bus is, read the [Guide](guide.md) first.
6
+
7
+ ## Add the plugin to the bus
8
+
9
+ **Problem.** Without help, a component writes `watch(query, (value) => bus.emit(queryChanged(value)))` and its own subscription in `onMounted` and `onUnmounted`. The same few lines are copied into every component, and each copy forgets something: the cleanup, the equality check, or the name of the subscription in the trace.
10
+
11
+ **When.** A Vue component sends values to the bus, reads events from it, or both.
12
+
13
+ `vuePlugin()` adds two functions to the bus. Take them out of the bus once, in the file that makes it, and import them where you need them:
14
+
15
+ ```js
16
+ // bus.js
17
+ import { createBus } from "nanoeffects";
18
+ import { vuePlugin } from "nanoeffects/vue";
19
+
20
+ // createBus — the event bus, created once outside Vue
21
+ // vuePlugin — adds watchEmitter and useEventRef to the bus
22
+ export const bus = createBus().use(vuePlugin());
23
+ export const { watchEmitter, useEventRef } = bus; // free functions: they do not read `this`
24
+ ```
25
+
26
+ ## Tell the bus that a value changed
27
+
28
+ <!-- docs-check: continue -->
29
+
30
+ `watchEmitter(source, event)` watches a `ref` or a getter and emits `event` with the new value after it changes. It does not emit when it is called, and it stops when the component unmounts. It is `watch` that ends with an emit, so it follows the rules of `watch`: several changes in one tick emit once, with the last value, and a `ref` that holds an object that you change in place does not trigger it.
31
+
32
+ ```js
33
+ // search.js
34
+ import { createAction } from "nanoeffects/actions";
35
+
36
+ // createAction — an event with a name; calling it builds { type, payload }
37
+ export const queryChanged = createAction("search/queryChanged");
38
+ export const searchLoaded = createAction("search/loaded");
39
+ ```
40
+
41
+ ```js
42
+ // query-box.js
43
+ import { ref } from "vue";
44
+ import { watchEmitter } from "./bus";
45
+ import { queryChanged } from "./search";
46
+
47
+ export const setup = () => {
48
+ const query = ref("");
49
+
50
+ // watchEmitter — emits queryChanged(query) when query changes, never on mount
51
+ watchEmitter(query, queryChanged);
52
+
53
+ return { query };
54
+ };
55
+ ```
56
+
57
+ The third argument takes the options `equals`, `traceId` and `traceGroupId`:
58
+
59
+ | Option | Use it when |
60
+ | ------ | ----------- |
61
+ | `equals(previous, next)` | A new object with the same fields should not emit: `{ equals: (a, b) => a.id === b.id }`. |
62
+ | `traceId` | You want the subscription to have a name in the [trace](tracing.md#show-which-subscription-began-a-chain). |
63
+ | `traceGroupId` | You want to name the whole flow that the emit starts. |
64
+
65
+ `watchEmitter` returns the function that stops it early, for use outside a component.
66
+
67
+ ## Show the result of an event
68
+
69
+ <!-- docs-check: continue -->
70
+
71
+ `useEventRef(event, initial)` returns a `ref` that starts as `initial`, and that every `event` of the bus sets to its payload. It stops listening when the component unmounts. A payload that is a function is stored, not called.
72
+
73
+ ```js
74
+ // found-list.js
75
+ import { useEventRef } from "./bus";
76
+ import { searchLoaded } from "./search";
77
+
78
+ export const setup = () => {
79
+ // useEventRef — like ref([]), but searchLoaded sets the value
80
+ const found = useEventRef(searchLoaded, []);
81
+
82
+ return { found };
83
+ };
84
+ ```
85
+
86
+ In TypeScript the type of the `ref` comes from the event: with `createAction<string[]>("search/loaded")` it is `Ref<string[]>`, and for an event with no payload type it comes from `initial`.
87
+
88
+ ### It is not a store
89
+
90
+ `useEventRef` is state of one component. Each component that calls it keeps its own copy of the last payload, and the bus keeps no values, so an event that came before the call is lost. To share a value between components, or to keep it for components that mount later, keep it in a store such as Pinia and write to it from a handler of the event. Or call `useEventRef` once in a component at the root and pass the `ref` down with `provide` and `inject`.
91
+
92
+ ## Where to go next
93
+
94
+ - The same two jobs for React: [Build a sign-up form in React](react.md).
95
+ - A policy in a component (a debounced save): in `<script setup>` make it once with [`withPolicy`](policies.md#use-a-policy-without-a-bus); Vue runs the setup once, so it needs no hook.
96
+ - Keep values in Pinia: [Connect Redux, Zustand, MobX, or Pinia](stores.md).