@blac/react 2.0.0 → 2.0.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 CHANGED
@@ -1,194 +1,272 @@
1
1
  # @blac/react
2
2
 
3
- A powerful React integration for the Blac state management library, providing seamless integration between React components and Blac's reactive state management system.
4
-
5
- ## Features
6
-
7
- - 🔄 Automatic re-rendering when relevant state changes
8
- - 🎯 Fine-grained dependency tracking
9
- - 🔍 Property access tracking for optimized updates
10
- - 🎨 TypeScript support with full type inference
11
- - ⚡️ Efficient state management with minimal boilerplate
12
- - 🔄 Support for isolated and shared bloc instances
13
- - 🎯 Custom dependency selectors for precise control
14
-
15
- ## Important: Arrow Functions Required
16
-
17
- All methods in Bloc or Cubit classes must use arrow function syntax (`method = () => {}`) instead of the traditional method syntax (`method() {}`). This is because arrow functions automatically bind `this` to the class instance. Without this binding, methods called from React components would lose their context and could not access instance properties like `this.state` or `this.emit()`.
18
-
19
- ```tsx
20
- // Correct way to define methods in your Bloc/Cubit classes
21
- class CounterBloc extends Cubit<CounterState> {
22
- increment = () => {
23
- this.emit({ ...this.state, count: this.state.count + 1 });
24
- }
25
-
26
- decrement = () => {
27
- this.emit({ ...this.state, count: this.state.count - 1 });
28
- }
29
- }
30
-
31
- // Incorrect way (will cause issues when called from React):
32
- class CounterBloc extends Cubit<CounterState> {
33
- increment() { // ❌ Will lose 'this' context when called from components
34
- this.emit({ ...this.state, count: this.state.count + 1 });
35
- }
36
- }
37
- ```
3
+ React integration for the BlaC state management library with automatic re-render optimization.
38
4
 
39
5
  ## Installation
40
6
 
41
7
  ```bash
42
- npm install @blac/react
8
+ npm install @blac/react @blac/core
43
9
  # or
44
- yarn add @blac/react
10
+ pnpm add @blac/react @blac/core
45
11
  # or
46
- pnpm add @blac/react
12
+ yarn add @blac/react @blac/core
47
13
  ```
48
14
 
49
15
  ## Quick Start
50
16
 
51
17
  ```tsx
18
+ import { Cubit } from '@blac/core';
52
19
  import { useBloc } from '@blac/react';
53
- import { CounterBloc } from './CounterBloc';
20
+
21
+ class CounterCubit extends Cubit<{ count: number }> {
22
+ constructor() {
23
+ super({ count: 0 });
24
+ }
25
+
26
+ increment = () => this.emit({ count: this.state.count + 1 });
27
+ decrement = () => this.emit({ count: this.state.count - 1 });
28
+ }
54
29
 
55
30
  function Counter() {
56
- const [state, counterBloc] = useBloc(CounterBloc);
31
+ const [state, counter] = useBloc(CounterCubit);
57
32
 
58
33
  return (
59
34
  <div>
60
35
  <p>Count: {state.count}</p>
61
- <button onClick={() => counterBloc.increment()}>Increment</button>
36
+ <button onClick={counter.increment}>+</button>
37
+ <button onClick={counter.decrement}>-</button>
62
38
  </div>
63
39
  );
64
40
  }
65
41
  ```
66
42
 
67
- ## Usage
43
+ ## Hooks
68
44
 
69
- ### Basic Usage
45
+ ### useBloc
70
46
 
71
- The `useBloc` hook provides a simple way to connect your React components to Blac's state management system:
47
+ Connects a component to a state container with automatic re-renders on state changes.
72
48
 
73
49
  ```tsx
74
- const [state, bloc] = useBloc(YourBloc);
50
+ const [state, bloc, ref] = useBloc(MyBloc);
75
51
  ```
76
52
 
77
- ### Advanced Configuration
53
+ **Returns:** `[state, bloc, ref]`
54
+
55
+ - `state` - Current state (reactive)
56
+ - `bloc` - The bloc instance for calling methods
57
+ - `ref` - Component reference for isolated instances
78
58
 
79
- The hook accepts configuration options for more control:
59
+ #### Tracking Modes
60
+
61
+ **Auto-tracking (default):** Automatically detects which properties you access and only re-renders when those change.
80
62
 
81
63
  ```tsx
82
- const [state, bloc] = useBloc(YourBloc, {
83
- id: 'custom-id', // Optional: Custom identifier for the bloc
84
- props: { /* ... */ }, // Optional: Props to pass to the bloc
85
- onMount: (bloc) => { /* ... */ }, // Optional: Callback when bloc is mounted (similar to useEffect(<>, []))
86
- dependencySelector: (newState, oldState) => [/* ... */], // Optional: Custom dependency tracking
64
+ function UserProfile() {
65
+ const [state, user] = useBloc(UserBloc);
66
+
67
+ // Only re-renders when state.name changes
68
+ // (state.email changes won't cause re-render)
69
+ return <h1>{state.name}</h1>;
70
+ }
71
+ ```
72
+
73
+ **Manual dependencies:** Explicit dependency array like `useEffect`.
74
+
75
+ ```tsx
76
+ function Counter() {
77
+ const [state] = useBloc(CounterBloc, {
78
+ dependencies: (state) => [state.count],
79
+ });
80
+
81
+ return <p>{state.count}</p>;
82
+ }
83
+ ```
84
+
85
+ **No tracking:** Returns full state, re-renders on any change.
86
+
87
+ ```tsx
88
+ function FullState() {
89
+ const [state] = useBloc(MyBloc, { autoTrack: false });
90
+
91
+ return <pre>{JSON.stringify(state)}</pre>;
92
+ }
93
+ ```
94
+
95
+ #### Options
96
+
97
+ ```tsx
98
+ useBloc(MyBloc, {
99
+ // Tracking mode
100
+ autoTrack: true, // Enable/disable auto-tracking (default: true)
101
+ dependencies: (state) => [state.prop], // Manual dependencies
102
+
103
+ // Instance management
104
+ instanceId: 'unique-id', // Custom instance identifier
105
+ props: { userId: 123 }, // Props passed to bloc
106
+
107
+ // Lifecycle callbacks
108
+ onMount: (bloc) => console.log('Mounted', bloc),
109
+ onUnmount: (bloc) => console.log('Unmounted', bloc),
87
110
  });
88
111
  ```
89
112
 
90
- ### Dependency Tracking
113
+ ### useBlocActions
91
114
 
92
- The hook automatically tracks which state properties are accessed in your component and only triggers re-renders when those specific properties change:
115
+ Connects to a state container without subscribing to state changes. Use for calling actions without re-renders, or for stateless containers.
93
116
 
94
117
  ```tsx
95
- function UserProfile() {
96
- const [state, userBloc] = useBloc(UserBloc);
118
+ const bloc = useBlocActions(MyBloc);
119
+ ```
97
120
 
98
- // Only re-renders when state.name changes
99
- return <h1>{state.name}</h1>;
121
+ **Use cases:**
122
+
123
+ ```tsx
124
+ // Stateless services (analytics, navigation, etc.)
125
+ function TrackButton() {
126
+ const analytics = useBlocActions(AnalyticsService);
127
+
128
+ return (
129
+ <button onClick={() => analytics.trackClick('button')}>Click me</button>
130
+ );
131
+ }
132
+
133
+ // Actions-only (no state subscription)
134
+ function IncrementButton() {
135
+ const counter = useBlocActions(CounterCubit);
136
+
137
+ return <button onClick={counter.increment}>+</button>;
100
138
  }
101
139
  ```
102
140
 
103
- This also works for getters on the Bloc or Cubit class:
141
+ #### Options
104
142
 
105
143
  ```tsx
106
- function UserProfile() {
107
- const [, userBloc] = useBloc(UserBloc);
144
+ useBlocActions(MyBloc, {
145
+ instanceId: 'unique-id', // Custom instance identifier
146
+ props: { config: value }, // Props passed to bloc
147
+ onMount: (bloc) => bloc.initialize(),
148
+ onUnmount: (bloc) => bloc.cleanup(),
149
+ });
150
+ ```
151
+
152
+ ## Instance Management
153
+
154
+ ### Shared Instances (Default)
155
+
156
+ By default, all components using the same bloc class share one instance:
157
+
158
+ ```tsx
159
+ function ComponentA() {
160
+ const [state] = useBloc(CounterCubit);
161
+ // Uses shared instance
162
+ }
163
+
164
+ function ComponentB() {
165
+ const [state] = useBloc(CounterCubit);
166
+ // Uses same shared instance
167
+ }
168
+ ```
169
+
170
+ ### Isolated Instances
171
+
172
+ For component-scoped state, use the `@blac({ isolated: true })` decorator:
173
+
174
+ ```tsx
175
+ import { Cubit, blac } from '@blac/core';
176
+
177
+ @blac({ isolated: true })
178
+ class FormCubit extends Cubit<FormState> {
179
+ // ...
180
+ }
181
+
182
+ function FormA() {
183
+ const [state] = useBloc(FormCubit);
184
+ // Gets its own instance
185
+ }
186
+
187
+ function FormB() {
188
+ const [state] = useBloc(FormCubit);
189
+ // Gets a different instance
190
+ }
191
+ ```
192
+
193
+ ### Named Instances
194
+
195
+ Share instances across specific components with `instanceId`:
196
+
197
+ ```tsx
198
+ function EditorA() {
199
+ const [state] = useBloc(EditorCubit, { instanceId: 'editor-1' });
200
+ }
201
+
202
+ function EditorB() {
203
+ const [state] = useBloc(EditorCubit, { instanceId: 'editor-1' });
204
+ // Same instance as EditorA
205
+ }
108
206
 
109
- // Only re-renders when the return value from the getter formattedName changes
110
- return <h1>{userBloc.formattedName}</h1>;
207
+ function EditorC() {
208
+ const [state] = useBloc(EditorCubit, { instanceId: 'editor-2' });
209
+ // Different instance
111
210
  }
112
211
  ```
113
212
 
114
- ### Custom Dependency Selector
213
+ ## Configuration
115
214
 
116
- For more control over when your component re-renders, you can provide a custom dependency selector:
215
+ Configure global behavior:
117
216
 
118
217
  ```tsx
119
- const [state, bloc] = useBloc(YourBloc, {
120
- dependencySelector: (newState, oldState) => [
121
- newState.specificField,
122
- newState.anotherField
123
- ]
218
+ import { configureBlacReact } from '@blac/react';
219
+
220
+ configureBlacReact({
221
+ autoTrack: true, // Enable auto-tracking by default (default: true)
124
222
  });
125
223
  ```
126
224
 
127
225
  ## API Reference
128
226
 
129
- ### useBloc Hook
227
+ ### useBloc
130
228
 
131
- ```typescript
132
- function useBloc<B extends BlocConstructor<BlocGeneric>>(
133
- bloc: B,
134
- options?: BlocHookOptions<InstanceType<B>>
135
- ): [BlocState<InstanceType<B>>, InstanceType<B>]
229
+ ```tsx
230
+ function useBloc<T extends StateContainerConstructor>(
231
+ BlocClass: T,
232
+ options?: UseBlocOptions<T>,
233
+ ): [ExtractState<T>, InstanceType<T>, ComponentRef];
136
234
  ```
137
235
 
138
- #### Options
236
+ ### useBlocActions
237
+
238
+ ```tsx
239
+ function useBlocActions<T extends StateContainerConstructor>(
240
+ BlocClass: T,
241
+ options?: UseBlocActionsOptions<InstanceType<T>>,
242
+ ): InstanceType<T>;
243
+ ```
244
+
245
+ ### UseBlocOptions
246
+
247
+ | Option | Type | Description |
248
+ | -------------- | ------------------ | ------------------------------------ |
249
+ | `autoTrack` | `boolean` | Enable auto-tracking (default: true) |
250
+ | `dependencies` | `(state) => any[]` | Manual dependency selector |
251
+ | `instanceId` | `string \| number` | Custom instance identifier |
252
+ | `props` | `P` | Props passed to bloc constructor |
253
+ | `onMount` | `(bloc) => void` | Called when component mounts |
254
+ | `onUnmount` | `(bloc) => void` | Called when component unmounts |
255
+
256
+ ### UseBlocActionsOptions
257
+
258
+ | Option | Type | Description |
259
+ | ------------ | ------------------ | -------------------------------- |
260
+ | `instanceId` | `string \| number` | Custom instance identifier |
261
+ | `props` | `P` | Props passed to bloc constructor |
262
+ | `onMount` | `(bloc) => void` | Called when component mounts |
263
+ | `onUnmount` | `(bloc) => void` | Called when component unmounts |
264
+
265
+ ## Compatibility
139
266
 
140
- - `id?: string` - Custom identifier for the bloc instance
141
- - `props?: InferPropsFromGeneric<B>` - Props to pass to the bloc
142
- - `onMount?: (bloc: B) => void` - Callback function invoked when the react component (the consumer) is connected to the bloc instance
143
- - `dependencySelector?: BlocHookDependencyArrayFn<B>` - Function to select dependencies for re-renders
144
-
145
- ## Best Practices
146
-
147
- 1. **Use Isolated Blocs**: When you need component-specific state, use isolated blocs:
148
- ```tsx
149
- class MyIsolatedBloc extends BlocBase {
150
- static isolated = true;
151
- // ... rest of your bloc implementation
152
- }
153
- ```
154
-
155
- 2. **Use Custom Identifiers**: When you need multiple independent instances of the same Bloc type, use custom identifiers to manage different state contexts:
156
- ```tsx
157
- // In a chat application with multiple chat rooms
158
- function ChatRoom({ roomId }: { roomId: string }) {
159
- const [state, chatBloc] = useBloc(ChatBloc, {
160
- id: `chat-${roomId}`, // Each room gets its own instance
161
- props: { roomId }
162
- });
163
-
164
- return (
165
- <div>
166
- <h2>Room: {roomId}</h2>
167
- {state.messages.map(msg => (
168
- <Message key={msg.id} message={msg} />
169
- ))}
170
- </div>
171
- );
172
- }
173
-
174
- // Usage:
175
- function ChatApp() {
176
- return (
177
- <div>
178
- <ChatRoom roomId="general" />
179
- <ChatRoom roomId="support" />
180
- </div>
181
- );
182
- }
183
- ```
184
-
185
- 3. **Optimize Re-renders**: Let the hook track dependencies automatically unless you have a specific need for custom dependency tracking.
186
-
187
- 4. **Type Safety**: Take advantage of TypeScript's type inference for better development experience and catch errors early.
188
-
189
- ## Contributing
190
-
191
- Contributions are welcome! Please feel free to submit a Pull Request.
267
+ - React 18.0+ or React 19.0+
268
+ - Works with React Compiler
269
+ - Supports concurrent rendering via `useSyncExternalStore`
192
270
 
193
271
  ## License
194
272
 
package/dist/index.cjs ADDED
@@ -0,0 +1,260 @@
1
+ let react = require("react");
2
+ let _blac_core = require("@blac/core");
3
+
4
+ //#region src/utils/instance-keys.ts
5
+ /**
6
+ * Instance key generation utilities for React integration
7
+ */
8
+ /**
9
+ * Generate an instance key for a bloc
10
+ *
11
+ * Logic:
12
+ * - If user provides instanceId, use it (convert number to string)
13
+ * - If isolated, generate or reuse a unique key for this component
14
+ * - Otherwise, return undefined (use default key)
15
+ *
16
+ * @param componentRef - React component reference (persists across remounts)
17
+ * @param isIsolated - Whether the bloc is isolated
18
+ * @param providedId - User-provided instance ID (from options)
19
+ * @returns Instance key string or undefined for default
20
+ */
21
+ function generateInstanceKey(componentRef, isIsolated, providedId) {
22
+ if (providedId !== void 0) return typeof providedId === "number" ? String(providedId) : providedId;
23
+ if (isIsolated) {
24
+ if (!componentRef.__blocInstanceId) componentRef.__blocInstanceId = (0, _blac_core.generateIsolatedKey)();
25
+ return componentRef.__blocInstanceId;
26
+ }
27
+ }
28
+
29
+ //#endregion
30
+ //#region src/config.ts
31
+ const defaultConfig = { autoTrack: true };
32
+ let globalConfig = { ...defaultConfig };
33
+ /**
34
+ * Configure global defaults for @blac/react hooks.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { configureBlacReact } from '@blac/react';
39
+ *
40
+ * // Disable auto-tracking globally
41
+ * configureBlacReact({
42
+ * autoTrack: false
43
+ * });
44
+ * ```
45
+ *
46
+ * @param config - Partial configuration to merge with defaults
47
+ */
48
+ function configureBlacReact(config) {
49
+ globalConfig = {
50
+ ...globalConfig,
51
+ ...config
52
+ };
53
+ }
54
+ /**
55
+ * Get the current global configuration.
56
+ * @internal
57
+ */
58
+ function getBlacReactConfig() {
59
+ return globalConfig;
60
+ }
61
+ /**
62
+ * Reset configuration to defaults (useful for testing).
63
+ * @internal
64
+ */
65
+ function resetBlacReactConfig() {
66
+ globalConfig = { ...defaultConfig };
67
+ }
68
+
69
+ //#endregion
70
+ //#region src/useBloc.ts
71
+ function determineTrackingMode(options) {
72
+ const globalConfig$1 = getBlacReactConfig();
73
+ const autoTrackEnabled = options?.autoTrack !== void 0 ? options.autoTrack : globalConfig$1.autoTrack;
74
+ return {
75
+ useManualDeps: options?.dependencies !== void 0,
76
+ autoTrackEnabled
77
+ };
78
+ }
79
+ /**
80
+ * React hook that connects a component to a state container with automatic re-render on state changes.
81
+ *
82
+ * Supports three tracking modes:
83
+ * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy
84
+ * - **Manual dependencies**: Explicit dependency array like useEffect
85
+ * - **No tracking**: Returns full state without optimization
86
+ *
87
+ * **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).
88
+ * Use `useBlocActions()` instead for stateless containers.
89
+ *
90
+ * @template T - The state container constructor type (inferred from BlocClass)
91
+ * @param BlocClass - The state container class to connect to (must not be stateless)
92
+ * @param options - Configuration options for tracking mode and instance management
93
+ * @returns Tuple with [state, bloc instance, ref]
94
+ *
95
+ * @example Basic usage
96
+ * ```ts
97
+ * const [state, myBloc, ref] = useBloc(MyBloc);
98
+ * ```
99
+ *
100
+ * @example With manual dependencies
101
+ * ```ts
102
+ * const [state, myBloc] = useBloc(MyBloc, {
103
+ * dependencies: (state) => [state.count]
104
+ * });
105
+ * ```
106
+ *
107
+ * @example With isolated instance
108
+ * ```ts
109
+ * const [state, myBloc] = useBloc(MyBloc, {
110
+ * instanceId: 'unique-id'
111
+ * });
112
+ * ```
113
+ */
114
+ function useBloc(BlocClass, options) {
115
+ const componentRef = (0, react.useRef)({});
116
+ const initialPropsRef = (0, react.useRef)(options?.props);
117
+ const isStateless = (0, _blac_core.isStatelessClass)(BlocClass);
118
+ const isIsolated = (0, _blac_core.isIsolatedClass)(BlocClass);
119
+ const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = (0, react.useMemo)(() => {
120
+ if (isStateless) {
121
+ console.error(`[BlaC] useBloc() does not support stateless containers. "${BlocClass.name}" is a StatelessCubit or StatelessVertex. Use useBlocActions() instead for stateless containers.`);
122
+ const instance$1 = (0, _blac_core.acquire)(BlocClass, "default");
123
+ return [
124
+ instance$1,
125
+ () => () => {},
126
+ () => ({}),
127
+ void 0,
128
+ null,
129
+ instance$1
130
+ ];
131
+ }
132
+ const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
133
+ const instance = (0, _blac_core.acquire)(BlocClass, instanceKey$1, { props: initialPropsRef.current });
134
+ if (initialPropsRef.current !== void 0) instance.updateProps(initialPropsRef.current);
135
+ const { useManualDeps, autoTrackEnabled } = determineTrackingMode(options);
136
+ let subscribeFn;
137
+ let getSnapshotFn;
138
+ let adapterState$1;
139
+ if (useManualDeps && options?.dependencies) {
140
+ adapterState$1 = (0, _blac_core.manualDepsInit)(instance);
141
+ subscribeFn = (0, _blac_core.manualDepsSubscribe)(instance, adapterState$1, { dependencies: options.dependencies });
142
+ getSnapshotFn = (0, _blac_core.manualDepsSnapshot)(instance, adapterState$1, { dependencies: options.dependencies });
143
+ } else if (!autoTrackEnabled) {
144
+ adapterState$1 = (0, _blac_core.noTrackInit)(instance);
145
+ subscribeFn = (0, _blac_core.noTrackSubscribe)(instance);
146
+ getSnapshotFn = (0, _blac_core.noTrackSnapshot)(instance);
147
+ } else {
148
+ adapterState$1 = (0, _blac_core.autoTrackInit)(instance);
149
+ subscribeFn = (0, _blac_core.autoTrackSubscribe)(instance, adapterState$1);
150
+ getSnapshotFn = (0, _blac_core.autoTrackSnapshot)(instance, adapterState$1);
151
+ }
152
+ return [
153
+ adapterState$1.proxiedBloc,
154
+ subscribeFn,
155
+ getSnapshotFn,
156
+ instanceKey$1,
157
+ adapterState$1,
158
+ instance
159
+ ];
160
+ }, [
161
+ BlocClass,
162
+ isStateless,
163
+ isIsolated,
164
+ options?.instanceId
165
+ ]);
166
+ const state = (0, react.useSyncExternalStore)(subscribe, getSnapshot);
167
+ const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
168
+ const externalDepsManager = (0, react.useRef)(new _blac_core.ExternalDepsManager());
169
+ (0, react.useEffect)(() => {
170
+ if (isStateless) return;
171
+ if (options?.props !== initialPropsRef.current) rawInstance.updateProps(options?.props);
172
+ }, [
173
+ options?.props,
174
+ rawInstance,
175
+ isStateless
176
+ ]);
177
+ (0, react.useEffect)(() => {
178
+ if (isStateless || !adapterState) return;
179
+ (0, _blac_core.disableGetterTracking)(adapterState, rawInstance);
180
+ externalDepsManager.current.updateSubscriptions(adapterState.getterState, rawInstance, forceUpdate);
181
+ });
182
+ (0, react.useEffect)(() => {
183
+ if (isStateless) return;
184
+ if (options?.onMount) options.onMount(bloc);
185
+ return () => {
186
+ externalDepsManager.current.cleanup();
187
+ if (options?.onUnmount) options.onUnmount(bloc);
188
+ (0, _blac_core.release)(BlocClass, instanceKey);
189
+ if (isIsolated && !rawInstance.isDisposed) rawInstance.dispose();
190
+ };
191
+ }, []);
192
+ return [
193
+ state,
194
+ bloc,
195
+ componentRef
196
+ ];
197
+ }
198
+
199
+ //#endregion
200
+ //#region src/useBlocActions.ts
201
+ /**
202
+ * React hook that connects to a state container instance without triggering re-renders.
203
+ * Use this when you only need to call actions on the bloc without subscribing to state changes.
204
+ *
205
+ * **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).
206
+ * It also works with regular Cubit/Vertex when you don't need state subscriptions.
207
+ *
208
+ * @template T - The state container constructor type (inferred from BlocClass)
209
+ * @param BlocClass - The state container class to connect to (supports both stateful and stateless)
210
+ * @param options - Configuration options for instance management and lifecycle
211
+ * @returns The state container instance for calling actions
212
+ *
213
+ * @example Basic usage with stateless container
214
+ * ```ts
215
+ * class AnalyticsService extends StatelessCubit {
216
+ * trackEvent(name: string) { ... }
217
+ * }
218
+ *
219
+ * const analytics = useBlocActions(AnalyticsService);
220
+ * analytics.trackEvent('page_view');
221
+ * ```
222
+ *
223
+ * @example With stateful container (no re-renders)
224
+ * ```ts
225
+ * const myBloc = useBlocActions(MyBloc);
226
+ * myBloc.someMethod(); // Won't cause re-renders
227
+ * ```
228
+ *
229
+ * @example With isolated instance
230
+ * ```ts
231
+ * const myBloc = useBlocActions(MyBloc, {
232
+ * instanceId: 'unique-id'
233
+ * });
234
+ * ```
235
+ */
236
+ function useBlocActions(BlocClass, options) {
237
+ const componentRef = (0, react.useRef)({});
238
+ const initialPropsRef = (0, react.useRef)(options?.props);
239
+ const [bloc, instanceKey] = (0, react.useMemo)(() => {
240
+ const isIsolated = (0, _blac_core.isIsolatedClass)(BlocClass);
241
+ const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
242
+ return [(0, _blac_core.acquire)(BlocClass, instanceKey$1, { props: initialPropsRef.current }), instanceKey$1];
243
+ }, [BlocClass]);
244
+ (0, react.useEffect)(() => {
245
+ if (options?.onMount) options.onMount(bloc);
246
+ return () => {
247
+ if (options?.onUnmount) options.onUnmount(bloc);
248
+ (0, _blac_core.release)(BlocClass, instanceKey);
249
+ if ((0, _blac_core.isIsolatedClass)(BlocClass) && !bloc.isDisposed) bloc.dispose();
250
+ };
251
+ }, []);
252
+ return bloc;
253
+ }
254
+
255
+ //#endregion
256
+ exports.configureBlacReact = configureBlacReact;
257
+ exports.resetBlacReactConfig = resetBlacReactConfig;
258
+ exports.useBloc = useBloc;
259
+ exports.useBlocActions = useBlocActions;
260
+ //# sourceMappingURL=index.cjs.map