@wirestate/react 0.6.2 → 0.7.0-experimental.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.
Files changed (158) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +185 -221
  3. package/cjs/development/index.js +462 -222
  4. package/cjs/development/index.js.map +1 -1
  5. package/cjs/development/lib.js +167 -45
  6. package/cjs/development/lib.js.map +1 -1
  7. package/cjs/development/test-utils.js +22 -11
  8. package/cjs/development/test-utils.js.map +1 -1
  9. package/cjs/production/index.js +1 -1
  10. package/cjs/production/index.js.map +1 -1
  11. package/cjs/production/lib.js +1 -1
  12. package/cjs/production/lib.js.map +1 -1
  13. package/cjs/production/test-utils.js +1 -1
  14. package/cjs/production/test-utils.js.map +1 -1
  15. package/esm/development/commands/use-command-caller.js +16 -3
  16. package/esm/development/commands/use-command-caller.js.map +1 -1
  17. package/esm/development/commands/use-command-handler.js +20 -4
  18. package/esm/development/commands/use-command-handler.js.map +1 -1
  19. package/esm/development/commands/use-optional-command-caller.js +20 -4
  20. package/esm/development/commands/use-optional-command-caller.js.map +1 -1
  21. package/esm/development/context/container-context.js +16 -0
  22. package/esm/development/context/container-context.js.map +1 -0
  23. package/esm/development/context/use-container.js +33 -0
  24. package/esm/development/context/use-container.js.map +1 -0
  25. package/esm/development/context/use-root-container.js +35 -0
  26. package/esm/development/context/use-root-container.js.map +1 -0
  27. package/esm/development/context/use-scope.js +31 -0
  28. package/esm/development/context/use-scope.js.map +1 -0
  29. package/esm/development/error/error-code.js +1 -3
  30. package/esm/development/error/error-code.js.map +1 -1
  31. package/esm/development/events/use-event-emitter.js +20 -4
  32. package/esm/development/events/use-event-emitter.js.map +1 -1
  33. package/esm/development/events/use-event.js +18 -4
  34. package/esm/development/events/use-event.js.map +1 -1
  35. package/esm/development/events/use-events-handler.js +18 -3
  36. package/esm/development/events/use-events-handler.js.map +1 -1
  37. package/esm/development/events/use-events.js +18 -4
  38. package/esm/development/events/use-events.js.map +1 -1
  39. package/esm/development/index.js +12 -10
  40. package/esm/development/index.js.map +1 -1
  41. package/esm/development/injection/use-injection.js +36 -0
  42. package/esm/development/injection/use-injection.js.map +1 -0
  43. package/esm/development/injection/use-optional-injection.js +40 -0
  44. package/esm/development/injection/use-optional-injection.js.map +1 -0
  45. package/esm/development/provision/container-activator.js +33 -0
  46. package/esm/development/provision/container-activator.js.map +1 -0
  47. package/esm/development/provision/container-provider.js +74 -0
  48. package/esm/development/provision/container-provider.js.map +1 -0
  49. package/esm/development/provision/sub-container-provider.js +69 -0
  50. package/esm/development/provision/sub-container-provider.js.map +1 -0
  51. package/esm/development/provision/use-container-provision-state.js +76 -0
  52. package/esm/development/provision/use-container-provision-state.js.map +1 -0
  53. package/esm/development/queries/use-optional-query-caller.js +16 -4
  54. package/esm/development/queries/use-optional-query-caller.js.map +1 -1
  55. package/esm/development/queries/use-optional-sync-query-caller.js +14 -3
  56. package/esm/development/queries/use-optional-sync-query-caller.js.map +1 -1
  57. package/esm/development/queries/use-query-caller.js +15 -3
  58. package/esm/development/queries/use-query-caller.js.map +1 -1
  59. package/esm/development/queries/use-query-handler.js +21 -5
  60. package/esm/development/queries/use-query-handler.js.map +1 -1
  61. package/esm/development/queries/use-sync-query-caller.js +15 -3
  62. package/esm/development/queries/use-sync-query-caller.js.map +1 -1
  63. package/esm/development/test-utils/with-container-provider.js +35 -0
  64. package/esm/development/test-utils/with-container-provider.js.map +1 -0
  65. package/esm/development/test-utils.js +1 -1
  66. package/esm/development/utils/shallow-equal-arrays.js +28 -0
  67. package/esm/development/utils/shallow-equal-arrays.js.map +1 -0
  68. package/esm/production/commands/use-command-caller.js +1 -1
  69. package/esm/production/commands/use-command-caller.js.map +1 -1
  70. package/esm/production/commands/use-command-handler.js +1 -1
  71. package/esm/production/commands/use-command-handler.js.map +1 -1
  72. package/esm/production/commands/use-optional-command-caller.js +1 -1
  73. package/esm/production/commands/use-optional-command-caller.js.map +1 -1
  74. package/esm/production/context/container-context.js +1 -0
  75. package/esm/production/context/container-context.js.map +1 -0
  76. package/esm/production/context/use-container.js +1 -0
  77. package/esm/production/context/use-container.js.map +1 -0
  78. package/esm/production/context/use-root-container.js +1 -0
  79. package/esm/production/context/use-root-container.js.map +1 -0
  80. package/esm/production/context/use-scope.js +1 -0
  81. package/esm/production/context/use-scope.js.map +1 -0
  82. package/esm/production/error/error-code.js +1 -1
  83. package/esm/production/error/error-code.js.map +1 -1
  84. package/esm/production/events/use-event-emitter.js +1 -1
  85. package/esm/production/events/use-event-emitter.js.map +1 -1
  86. package/esm/production/events/use-event.js +1 -1
  87. package/esm/production/events/use-event.js.map +1 -1
  88. package/esm/production/events/use-events-handler.js +1 -1
  89. package/esm/production/events/use-events-handler.js.map +1 -1
  90. package/esm/production/events/use-events.js +1 -1
  91. package/esm/production/events/use-events.js.map +1 -1
  92. package/esm/production/index.js +1 -1
  93. package/esm/production/injection/use-injection.js +1 -0
  94. package/esm/production/injection/use-injection.js.map +1 -0
  95. package/esm/production/injection/use-optional-injection.js +1 -0
  96. package/esm/production/injection/use-optional-injection.js.map +1 -0
  97. package/esm/production/provision/container-activator.js +1 -0
  98. package/esm/production/provision/container-activator.js.map +1 -0
  99. package/esm/production/provision/container-provider.js +1 -0
  100. package/esm/production/provision/container-provider.js.map +1 -0
  101. package/esm/production/provision/sub-container-provider.js +1 -0
  102. package/esm/production/provision/sub-container-provider.js.map +1 -0
  103. package/esm/production/provision/use-container-provision-state.js +1 -0
  104. package/esm/production/provision/use-container-provision-state.js.map +1 -0
  105. package/esm/production/queries/use-optional-query-caller.js +1 -1
  106. package/esm/production/queries/use-optional-query-caller.js.map +1 -1
  107. package/esm/production/queries/use-optional-sync-query-caller.js +1 -1
  108. package/esm/production/queries/use-optional-sync-query-caller.js.map +1 -1
  109. package/esm/production/queries/use-query-caller.js +1 -1
  110. package/esm/production/queries/use-query-caller.js.map +1 -1
  111. package/esm/production/queries/use-query-handler.js +1 -1
  112. package/esm/production/queries/use-query-handler.js.map +1 -1
  113. package/esm/production/queries/use-sync-query-caller.js +1 -1
  114. package/esm/production/queries/use-sync-query-caller.js.map +1 -1
  115. package/esm/production/test-utils/with-container-provider.js +1 -0
  116. package/esm/production/test-utils/with-container-provider.js.map +1 -0
  117. package/esm/production/test-utils.js +1 -1
  118. package/esm/production/utils/shallow-equal-arrays.js +1 -0
  119. package/esm/production/utils/shallow-equal-arrays.js.map +1 -0
  120. package/index.d.ts +554 -137
  121. package/package.json +1 -1
  122. package/test-utils.d.ts +19 -8
  123. package/esm/development/provision/create-injectables-provider.js +0 -101
  124. package/esm/development/provision/create-injectables-provider.js.map +0 -1
  125. package/esm/development/provision/ioc-context.js +0 -11
  126. package/esm/development/provision/ioc-context.js.map +0 -1
  127. package/esm/development/provision/ioc-provider.js +0 -50
  128. package/esm/development/provision/ioc-provider.js.map +0 -1
  129. package/esm/development/provision/use-container-revision.js +0 -13
  130. package/esm/development/provision/use-container-revision.js.map +0 -1
  131. package/esm/development/provision/use-container.js +0 -13
  132. package/esm/development/provision/use-container.js.map +0 -1
  133. package/esm/development/provision/use-injection.js +0 -22
  134. package/esm/development/provision/use-injection.js.map +0 -1
  135. package/esm/development/provision/use-ioc-context.js +0 -21
  136. package/esm/development/provision/use-ioc-context.js.map +0 -1
  137. package/esm/development/provision/use-optional-injection.js +0 -29
  138. package/esm/development/provision/use-optional-injection.js.map +0 -1
  139. package/esm/development/test-utils/with-ioc-provider.js +0 -24
  140. package/esm/development/test-utils/with-ioc-provider.js.map +0 -1
  141. package/esm/production/provision/create-injectables-provider.js +0 -1
  142. package/esm/production/provision/create-injectables-provider.js.map +0 -1
  143. package/esm/production/provision/ioc-context.js +0 -1
  144. package/esm/production/provision/ioc-context.js.map +0 -1
  145. package/esm/production/provision/ioc-provider.js +0 -1
  146. package/esm/production/provision/ioc-provider.js.map +0 -1
  147. package/esm/production/provision/use-container-revision.js +0 -1
  148. package/esm/production/provision/use-container-revision.js.map +0 -1
  149. package/esm/production/provision/use-container.js +0 -1
  150. package/esm/production/provision/use-container.js.map +0 -1
  151. package/esm/production/provision/use-injection.js +0 -1
  152. package/esm/production/provision/use-injection.js.map +0 -1
  153. package/esm/production/provision/use-ioc-context.js +0 -1
  154. package/esm/production/provision/use-ioc-context.js.map +0 -1
  155. package/esm/production/provision/use-optional-injection.js +0 -1
  156. package/esm/production/provision/use-optional-injection.js.map +0 -1
  157. package/esm/production/test-utils/with-ioc-provider.js +0 -1
  158. package/esm/production/test-utils/with-ioc-provider.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ ## 0.7.0
2
+
3
+ - Add `useScope` in `@wirestate/react`
4
+ - New lit elements modules - `@wirestate/lit` and `@wirestate/lit-signals`
5
+ - `EventBus`: add `unsubscribe` method for explicit handler removal by reference
6
+ - `QueryBus`: add `unregister` method for explicit handler removal by type and reference
7
+ - `CommandBus`: add `unregister` method for explicit handler removal by type and reference
8
+ - `WireScope`: add new event/command/query subscribe-unsubscribe methods
9
+ - Export more alias / methods from `@wirestate/core`
10
+ - Export more alias / methods from `@wirestate/react-mobx`
11
+ - Export missing methods typing for `@wirestate/core`
12
+ - Extensive JSDoc coverage for wirestate packages
13
+ - `createIocContainer`: Added ability to instantly provide and activate entries, targeted seeds
14
+ - `createInjectablesProvider`: Removed.
15
+ - `IocProvider`: Removed
16
+ - `useRootContainer`: Added separate hook for store management in React tree
17
+ - `ContainerProvider`: Simpler provider for containers.
18
+ - `SubContainerProvider`: Added component solving problems of removed `createInjectablesProvider`
19
+ - `ContainerActivator`: Added separate activation component
20
+
21
+ ## 0.6.3
22
+
23
+ - Update readme files for each module
24
+
1
25
  ## 0.6.2
2
26
 
3
27
  - Corrected build system, react package structure
@@ -55,6 +79,6 @@
55
79
  - useService -> useInjection
56
80
  - AbstractService::getService -> AbstractService::resolve
57
81
 
58
- ## 0.1.1
82
+ ## 0.1.0
59
83
 
60
84
  - Initial release
package/README.md CHANGED
@@ -1,319 +1,283 @@
1
- # <a href='https://www.npmjs.com/package/wirestate'> wirestate </a>
1
+ # @wirestate/react [[monorepo](https://github.com/Neloreck/wirestate)] [[docs](https://neloreck.github.io/wirestate/)]
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/wirestate.svg?style=flat-square)](https://www.npmjs.com/package/wirestate)
4
- [![language-ts](https://img.shields.io/badge/language-typescript-blue.svg?style=flat)](https://github.com/Neloreck/wirestate/search?l=typescript)
3
+ [![npm](https://img.shields.io/npm/v/@wirestate/react.svg?style=flat-square)](https://www.npmjs.com/package/@wirestate/react)
5
4
  [![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Neloreck/wirestate/blob/master/LICENSE)
6
5
 
7
- `wirestate` is a reactivity-independent state management framework for React. It integrates **InversifyJS** for robust Dependency Injection,
8
- providing IOC/DI/indirection based architecture based on concepts of Services, Events, Commands, and Queries.
9
-
10
- It optionally works with **MobX**, **Signals**, or other custom reactivity implementations.
11
-
12
- ## Architecture & Core Concepts
13
-
14
- Designed for complex applications, `wirestate` enforces a clear separation of concerns:
15
-
16
- - **Services**: Singleton-scoped logic units that hold state and business logic.
17
- - **Dependency Injection**: First-class InversifyJS integration for decoupled, testable code.
18
- - **Reactivity**: Independent state tracking (optional integration with MobX, Signals, etc.).
19
- - **Events**: Fire-and-forget communication for cross-service side effects.
20
- - **Commands**: Encapsulated write operations with standardized execution status (pending, settled, error).
21
- - **Queries**: Synchronous or asynchronous request-response patterns for data retrieval.
22
- - **Lifecycle Management**: Automated services provision within react tree, activation/deactivation lifecycle.
23
-
24
- ## Requirements
25
-
26
- - `react >= 16.8.0`
27
- - `reflect-metadata` (must be imported at application entry)
6
+ React integration for wirestate. Providers and hooks for injecting services and communicating through events, commands, and queries.
28
7
 
29
8
  ## Installation
30
9
 
31
10
  ```bash
32
- npm install --save @wirestate/core reflect-metadata
11
+ npm install @wirestate/core @wirestate/react reflect-metadata
33
12
  ```
34
13
 
35
- ### For react-mobx
14
+ ## Providers
36
15
 
37
- ```bash
38
- npm install --save @wirestate/react @wirestate/react-mobx mobx mobx-react-lite
39
- ```
16
+ ### `ContainerProvider`
40
17
 
41
- ### For signals
18
+ Root provider. Creates the top-level IoC container. Place once near the root of your application.
42
19
 
43
- ```bash
44
- npm install --save @wirestate/react @wirestate/react-signals @preact/signals-react
45
- npm install --save-dev @preact/signals-react-transform
46
- ```
20
+ With globally declared container:
47
21
 
48
- ## Quick Start with mobx
22
+ ```tsx
23
+ import { createContainer, Container } from "@wirestate/core";
24
+ import { ContainerProvider } from "@wirestate/react";
25
+ import { CounterService, LoggerService } from "./services";
49
26
 
50
- ### 1. Define a Service
27
+ const container: Container = createContainer({
28
+ entries: [CounterService, LoggerService],
29
+ activate: [LoggerService],
30
+ });
51
31
 
52
- Services are standard classes decorated with `@Injectable`. Use `WireScope` to interact with the framework.
32
+ export function Application() {
33
+ return (
34
+ <ContainerProvider container={container}>
35
+ <SomeComponent />
36
+ </ContainerProvider>
37
+ );
38
+ }
39
+ ```
53
40
 
54
- ```typescript
55
- import { Injectable, Inject, WireScope, OnEvent, OnCommand, OnQuery } from '@wirestate/core';
56
- import { makeObservable, Observable, Action } from '@wirestate/react-mobx';
41
+ With locally declared container:
57
42
 
58
- @Injectable()
59
- export class CounterService {
60
- @Observable()
61
- public count: number = 0;
43
+ ```tsx
44
+ import { createContainer, Container } from "@wirestate/core";
45
+ import { ContaierProvider, ContainerActivator, useRootContainer } from "@wirestate/react";
46
+ import { CounterService, LoggerService } from "./services";
62
47
 
63
- public constructor(
64
- @Inject(WireScope)
65
- private scope: WireScope
66
- ) {
67
- makeObservable(this);
68
- }
48
+ export function Application() {
49
+ const container: Container = useRootContainer(
50
+ () =>
51
+ createContainer({
52
+ entries: [CounterService, LoggerService],
53
+ }),
54
+ []
55
+ );
69
56
 
70
- @Action()
71
- public increment(amount: number = 1): void {
72
- this.count += amount;
73
- }
57
+ return (
58
+ <ContaierProvider container={container}>
59
+ <ContainerActivator activate={[LoggerService]}>
60
+ <SomeComponent />
61
+ </ContainerActivator>
62
+ </ContaierProvider>
63
+ );
64
+ }
65
+ ```
74
66
 
75
- @Action()
76
- public reset(): void {
77
- this.count = 0;
78
- }
67
+ ### `useRootContainer(factory, deps)`
79
68
 
80
- @OnCommand('INCREMENT')
81
- public onIncrementCommand(amount: number = 1): void {
82
- this.increment(amount);
83
- }
69
+ Creates and memoizes a root container for the component instance.
70
+ The factory runs again only when `deps` change or on dev mode HMR refreshment.
84
71
 
85
- @OnQuery('GET_TOTAL')
86
- public onGetTotal(): number {
87
- return this.count;
88
- }
72
+ ```tsx
73
+ import { Container, createContainer } from "@wirestate/core";
74
+ import { useRootContainer, ContainerProvider } from "@wirestate/react";
75
+
76
+ function Root() {
77
+ const container: Container = useRootContainer(
78
+ () =>
79
+ createContainer({
80
+ entries: [CounterService, LoggerService],
81
+ }),
82
+ []
83
+ );
89
84
 
90
- @OnEvent('RESET')
91
- public onResetEvent(): void {
92
- this.reset();
93
- }
85
+ return (
86
+ <ContainerProvider container={container}>
87
+ <SomeComponent />
88
+ </ContainerProvider>
89
+ );
94
90
  }
95
91
  ```
96
92
 
97
- ### 2. Configure the Provider
93
+ ### `createInjectablesProvider`
98
94
 
99
- Bind services at any level of the component tree.
100
- Lifetimes are managed automatically.
95
+ Creates a component that binds a set of services into a child container scoped to the component's lifetime.
96
+ Services are activated on mount and deactivated on unmount. Expects to be under `ContainerProvider` tree.
101
97
 
102
98
  ```tsx
103
- import { IocProvider, createInjectablesProvider } from '@wirestate/react';
104
- import { CounterService } from './CounterService';
99
+ import { createInjectablesProvider } from "@wirestate/react";
100
+ import { CounterService, LoggerService } from "./services";
105
101
 
106
- const MainProvider = createInjectablesProvider([CounterService]);
102
+ const InjectionProvider = createInjectablesProvider([CounterService, LoggerService]);
107
103
 
108
- export function Application() {
104
+ export function CounterPage() {
109
105
  return (
110
- <IocProvider>
111
- <MainProvider>
112
- <CounterView />
113
- </MainProvider>
114
- </IocProvider>
106
+ <InjectionProvider>
107
+ <CounterView />
108
+ </InjectionProvider>
115
109
  );
116
110
  }
117
111
  ```
118
112
 
119
- ### 3. Consume in Components
113
+ **Props:**
120
114
 
121
- Directly use services and rely on mobx reactivity.
122
- Or use specialized hooks for communication without direct references.
115
+ | Prop | Type | Description |
116
+ | ------- | ------------- | ----------------------------------------------------------- |
117
+ | `seeds` | `SeedEntries` | Per-service seeds, e.g. `[[CounterService, { count: 10 }]]` |
123
118
 
124
- ```tsx
125
- import { useInjection, useCommandCaller, useEventEmitter } from '@wirestate/react';
126
- import { observer } from '@wirestate/react-mobx';
127
- import { CounterService } from './CounterService';
119
+ `seeds` are applied on first render only.
120
+
121
+ ### `ContainerActivator`
128
122
 
129
- export const CounterView = observer(() => {
130
- const service = useInjection(CounterService);
131
- const call = useCommandCaller();
132
- const emit = useEventEmitter();
123
+ Resolves a list of already bound services from the current container before rendering children.
124
+ Useful when services should be eagerly activated for a subtree.
133
125
 
126
+ ```tsx
127
+ import { ContainerActivator } from "@wirestate/react";
128
+ import { CounterService, LoggerService } from "./services";
129
+
130
+ export function CounterPage() {
134
131
  return (
135
- <div>
136
- <p>Count: {service.count}</p>
137
- <button onClick={() => service.increment(5)}>Add 1 (Method)</button>
138
- <button onClick={() => call('INCREMENT', 5)}>Add 5 (Command)</button>
139
- <button onClick={() => service.reset()}>Reset (Method)</button>
140
- <button onClick={() => emit('RESET')}>Reset (Event)</button>
141
- </div>
132
+ <ContainerActivator activate={[CounterService, LoggerService]}>
133
+ <CounterView />
134
+ </ContainerActivator>
142
135
  );
143
- });
136
+ }
144
137
  ```
145
138
 
146
- ## Quick Start with signals
139
+ `ContainerActivator` runs activation once per container instance. If the container changes, activation runs again.
140
+
141
+ ## Injection hooks
147
142
 
148
- ### 1. Define a Service
143
+ ### `useInjection(token)`
149
144
 
150
- Services use `signal` and `computed` for state management.
145
+ Resolves a value from the nearest container. Re-resolves when the container resets.
146
+
147
+ ```tsx
148
+ import { useInjection } from "@wirestate/react";
149
+ import { CounterService } from "./services";
151
150
 
152
- ```typescript
153
- import { Injectable, Inject, WireScope, OnEvent, OnCommand, OnQuery } from '@wirestate/core';
154
- import { signal, computed, Signal, ReadonlySignal } from '@wirestate/react-signals';
151
+ function CounterView() {
152
+ const counter = useInjection(CounterService);
153
+ return <span>{counter.count}</span>;
154
+ }
155
+ ```
155
156
 
156
- @Injectable()
157
- export class CounterService {
158
- public readonly count: Signal<number> = signal(0);
159
- public readonly isEven: ReadonlySignal<boolean> = computed(() => this.count.value % 2 === 0);
157
+ ### `useOptionalInjection(token)`
160
158
 
161
- public constructor(
162
- @Inject(WireScope)
163
- private scope: WireScope
164
- ) {}
159
+ Same as `useInjection` but returns `null` if the token is not bound.
165
160
 
166
- public increment(amount: number = 1): void {
167
- this.count.value += amount;
168
- }
161
+ ## Event hooks
169
162
 
170
- public reset(): void {
171
- this.count.value = 0;
172
- }
163
+ ### `useEventEmitter()`
173
164
 
174
- @OnCommand('INCREMENT')
175
- public onIncrementCommand(amount: number = 1): void {
176
- this.increment(amount);
177
- }
165
+ Returns a function that emits an event into the current container's event bus.
178
166
 
179
- @OnQuery('GET_TOTAL')
180
- public onGetTotal(): number {
181
- return this.count.value;
182
- }
167
+ ```tsx
168
+ const emit = useEventEmitter();
183
169
 
184
- @OnEvent('RESET')
185
- public onResetEvent(): void {
186
- this.reset();
187
- }
188
- }
170
+ emit("RESET");
171
+ emit("ADD", { amount: 5 });
189
172
  ```
190
173
 
191
- ### 2. Configure the Provider
174
+ ### `useEvent(type, handler)`
192
175
 
193
- The provider configuration remains the same regardless of the reactivity implementation.
176
+ Subscribes a handler to a single event type for the lifetime of the component.
194
177
 
195
178
  ```tsx
196
- import { IocProvider, createInjectablesProvider } from '@wirestate/react';
197
- import { CounterService } from './CounterService';
179
+ useEvent("RESET", (event) => {
180
+ console.log(event.type, event.payload);
181
+ });
182
+ ```
198
183
 
199
- const MainProvider = createInjectablesProvider([CounterService]);
184
+ ### `useEvents(types, handler)`
200
185
 
201
- export function Application() {
202
- return (
203
- <IocProvider>
204
- <MainProvider>
205
- <CounterView />
206
- </MainProvider>
207
- </IocProvider>
208
- );
209
- }
186
+ Subscribes to multiple event types with a single handler.
187
+
188
+ ```tsx
189
+ useEvents(["RESET", "CLEAR"], (event) => {
190
+ console.log(event.type, event.payload);
191
+ });
210
192
  ```
211
193
 
212
- ### 3. Consume in Components
194
+ ### `useEventsHandler(handler)`
213
195
 
214
- Access signals directly in components. Reactivity is handled by the signals transform or manual subscription.
196
+ Subscribes to all events. The handler receives the event type and payload.
215
197
 
216
198
  ```tsx
217
- import { useInjection, useCommandCaller, useEventEmitter } from '@wirestate/react';
218
- import { CounterService } from './CounterService';
199
+ useEventsHandler((event) => {
200
+ logger.log(event.type, event.payload);
201
+ });
202
+ ```
219
203
 
220
- export function CounterView() {
221
- const service = useInjection(CounterService);
222
- const call = useCommandCaller();
223
- const emit = useEventEmitter();
204
+ ## Command hooks
224
205
 
225
- return (
226
- <div>
227
- <p>Count: {service.count}</p>
228
- <p>Even: {service.isEven.value ? 'Yes' : 'No'}</p>
229
- <button onClick={() => service.increment(5)}>Add 1 (Method)</button>
230
- <button onClick={() => call('INCREMENT', 5)}>Add 5 (Command)</button>
231
- <button onClick={() => service.reset()}>Reset (Method)</button>
232
- <button onClick={() => emit('RESET')}>Reset (Event)</button>
233
- </div>
234
- );
206
+ ### `useCommandCaller()`
207
+
208
+ Returns a function that dispatches a command and waits for its result.
209
+
210
+ ```tsx
211
+ const call = useCommandCaller();
212
+
213
+ async function handleClick() {
214
+ await call("LOGIN", { username: "alice" }).task;
235
215
  }
236
216
  ```
237
217
 
238
- ## Advanced Usage
218
+ ### `useOptionalCommandCaller()`
239
219
 
240
- ### Seeding Shared Initial State
220
+ Same as `useCommandCaller` but returns `null` if no handler is registered.
241
221
 
242
- `wirestate` supports providing initial data (seeds) to services during activation.
222
+ ### `useCommandHandler(type, handler)`
243
223
 
244
- ```tsx
245
- const MainProvider = createInjectablesProvider([CounterService]);
224
+ Registers a command handler from a component for the lifetime of the component.
246
225
 
247
- <IocProvider>
248
- <MainProvider seed={{ initialCount: 100 }}>
249
- <CounterView />
250
- </MainProvider>
251
- </IocProvider>
226
+ ```tsx
227
+ useCommandHandler("SCROLL_TOP", () => {
228
+ window.scrollTo(0, 0);
229
+ });
252
230
  ```
253
231
 
254
- In the service:
232
+ ## Query hooks
255
233
 
256
- ```typescript
257
- import { Injectable, Inject, SEED } from 'wirestate';
234
+ ### `useQueryCaller()`
258
235
 
259
- @Injectable()
260
- export class CounterService {
261
- // ...
262
- public constructor(
263
- @Inject(SEED)
264
- initialState: { initialCount: number }
265
- ) {
266
- this.count = seed.initialCount;
267
- }
268
- }
236
+ Returns an async function that calls a query handler and resolves its return value.
237
+
238
+ ```tsx
239
+ const query = useQueryCaller();
240
+ const items = await query("GET_ITEMS");
269
241
  ```
270
242
 
271
- ### Seeding Bound Initial State
243
+ ### `useSyncQueryCaller()`
272
244
 
273
- `wirestate` supports providing initial data (seeds) to services during activation.
245
+ Same as `useQueryCaller` but calls a synchronous handler.
274
246
 
275
- ```tsx
276
- const MainProvider = createInjectablesProvider([CounterService]);
247
+ ### `useOptionalQueryCaller()` / `useOptionalSyncQueryCaller()`
277
248
 
278
- <IocProvider>
279
- <MainProvider seeds={[[CounterService, { count: 10 }]]}>
280
- <CounterView />
281
- </MainProvider>
282
- </IocProvider>
283
- ```
249
+ Return `null` when no handler is registered instead of throwing.
284
250
 
285
- In the service:
251
+ ### `useQueryHandler(type, handler)`
286
252
 
287
- ```typescript
288
- import { Injectable, Inject, WireScope } from 'wirestate';
253
+ Registers a query handler from a component.
289
254
 
290
- @Injectable()
291
- export class CounterService {
292
- // ...
293
- public constructor(@Inject(WireScope) scope: WireScope) {
294
- this.count = scope.getSeed(CounterService).count;
295
- }
296
- }
255
+ ```tsx
256
+ useQueryHandler("GET_SCROLL_POS", () => window.scrollY);
297
257
  ```
298
258
 
299
- ### Service Lifecycle
259
+ ## Container hooks
300
260
 
301
- Use decorators to handle initialization and cleanup.
261
+ ### `useContainer()`
302
262
 
303
- ```typescript
304
- import { OnActivated, OnDeactivation } from 'wirestate';
263
+ Returns the nearest `Container` instance. Useful for advanced manual resolution.
305
264
 
306
- @OnActivated()
307
- public onActivated(): void {
308
- // Start polling, fetch initial data, etc.
309
- }
265
+ ### `useContainerRevision()`
310
266
 
311
- @OnDeactivation()
312
- public onDeactivation(): void {
313
- // Cleanup subscriptions
314
- }
267
+ Returns a counter that increments each time the container is reset. Use to trigger effects when the container changes.
268
+
269
+ ### `useScope()`
270
+
271
+ Returns the current `WireScope` linked to the nearest container.
272
+
273
+ ## Test utilities
274
+
275
+ ```ts
276
+ import { withContainerProvider } from "@wirestate/react/test-utils";
315
277
  ```
316
278
 
279
+ `withContainerProvider(children, container?, seed?)` — wraps a React tree with an `ContainerProvider` for use in tests.
280
+
317
281
  ## License
318
282
 
319
283
  MIT