@blac/react 2.0.0-rc-11 → 2.0.0-rc-14

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 DELETED
@@ -1,265 +0,0 @@
1
- # @blac/react
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 with access to state, previous state, and instance
14
- - 🚀 Optimized re-rendering with intelligent snapshot comparison
15
-
16
- ## Important: Arrow Functions Required
17
-
18
- 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()`.
19
-
20
- ```tsx
21
- // Correct way to define methods in your Bloc/Cubit classes
22
- class CounterBloc extends Cubit<CounterState> {
23
- increment = () => {
24
- this.emit({ ...this.state, count: this.state.count + 1 });
25
- }
26
-
27
- decrement = () => {
28
- this.emit({ ...this.state, count: this.state.count - 1 });
29
- }
30
- }
31
-
32
- // Incorrect way (will cause issues when called from React):
33
- class CounterBloc extends Cubit<CounterState> {
34
- increment() { // ❌ Will lose 'this' context when called from components
35
- this.emit({ ...this.state, count: this.state.count + 1 });
36
- }
37
- }
38
- ```
39
-
40
- ## Installation
41
-
42
- ```bash
43
- npm install @blac/react
44
- # or
45
- yarn add @blac/react
46
- # or
47
- pnpm add @blac/react
48
- ```
49
-
50
- ## Quick Start
51
-
52
- ```tsx
53
- import { useBloc } from '@blac/react';
54
- import { CounterBloc } from './CounterBloc';
55
-
56
- function Counter() {
57
- const [state, counterBloc] = useBloc(CounterBloc);
58
-
59
- return (
60
- <div>
61
- <p>Count: {state.count}</p>
62
- <button onClick={() => counterBloc.increment()}>Increment</button>
63
- </div>
64
- );
65
- }
66
- ```
67
-
68
- ## Usage
69
-
70
- ### Basic Usage
71
-
72
- The `useBloc` hook provides a simple way to connect your React components to Blac's state management system:
73
-
74
- ```tsx
75
- const [state, bloc] = useBloc(YourBloc);
76
- ```
77
-
78
- ### Advanced Configuration
79
-
80
- The hook accepts configuration options for more control:
81
-
82
- ```tsx
83
- const [state, bloc] = useBloc(YourBloc, {
84
- id: 'custom-id', // Optional: Custom identifier for the bloc
85
- props: { /* ... */ }, // Optional: Props to pass to the bloc
86
- onMount: (bloc) => { /* ... */ }, // Optional: Callback when bloc is mounted (similar to useEffect(<>, []))
87
- selector: (currentState, previousState, instance) => [/* ... */], // Optional: Custom dependency tracking
88
- });
89
- ```
90
-
91
- ### Automatic Dependency Tracking
92
-
93
- The hook automatically tracks which state properties and bloc instance properties are accessed in your component and only triggers re-renders when those specific values change:
94
-
95
- ```tsx
96
- function UserProfile() {
97
- const [state, userBloc] = useBloc(UserBloc);
98
-
99
- // Only re-renders when state.name changes
100
- return <h1>{state.name}</h1>;
101
- }
102
- ```
103
-
104
- This also works for getters and computed properties on the Bloc or Cubit class:
105
-
106
- ```tsx
107
- function UserProfile() {
108
- const [state, userBloc] = useBloc(UserBloc);
109
-
110
- // Only re-renders when:
111
- // - state.firstName changes, OR
112
- // - state.lastName changes (because the getter accesses these properties)
113
- return <h1>{userBloc.fullName}</h1>; // Assuming fullName is a getter
114
- }
115
- ```
116
-
117
- #### How It Works
118
-
119
- The dependency tracking system uses JavaScript Proxies to monitor property access during component renders:
120
-
121
- 1. **State Properties**: When you access `state.propertyName`, it's automatically tracked
122
- 2. **Instance Properties**: When you access `bloc.computedValue`, it's automatically tracked
123
- 3. **Intelligent Comparison**: The system separately tracks state dependencies and instance dependencies to handle edge cases where properties are dynamically added/removed
124
- 4. **Optimized Updates**: Components only re-render when tracked dependencies actually change their values
125
-
126
- #### Configuring Proxy Tracking
127
-
128
- By default, BlaC uses proxy-based dependency tracking for optimal performance. You can disable this globally if needed:
129
-
130
- ```tsx
131
- import { Blac } from '@blac/core';
132
-
133
- // Disable automatic dependency tracking globally
134
- Blac.setConfig({ proxyDependencyTracking: false });
135
-
136
- // Now components will re-render on ANY state change
137
- // unless you provide manual dependencies
138
- ```
139
-
140
- When proxy tracking is disabled:
141
- - Components re-render on any state change (similar to traditional state management)
142
- - Manual dependencies via the `selector` option still work as expected
143
- - Useful for debugging or when proxy behavior causes issues
144
-
145
- For more configuration options, see the [@blac/core documentation](https://www.npmjs.com/package/@blac/core).
146
-
147
- ### Custom Dependency Selector
148
-
149
- For more control over when your component re-renders, you can provide a custom dependency selector. The selector function receives the current state, previous state, and bloc instance, and should return an array of values to track:
150
-
151
- ```tsx
152
- const [state, bloc] = useBloc(YourBloc, {
153
- selector: (currentState, previousState, instance) => [
154
- currentState.specificField,
155
- currentState.anotherField,
156
- instance.computedValue // You can also track computed properties from the bloc instance
157
- ]
158
- });
159
- ```
160
-
161
- The component will only re-render when any of the values in the returned array change (using `Object.is` comparison, similar to React's `useEffect` dependency array).
162
-
163
- #### Examples of Custom Selectors
164
-
165
- **Track only specific state properties:**
166
- ```tsx
167
- const [state, userBloc] = useBloc(UserBloc, {
168
- selector: (currentState) => [
169
- currentState.name,
170
- currentState.email
171
- ] // Only re-render when name or email changes, ignore other properties
172
- });
173
- ```
174
-
175
- **Track computed values:**
176
- ```tsx
177
- const [state, shoppingCartBloc] = useBloc(ShoppingCartBloc, {
178
- selector: (currentState, previousState, instance) => [
179
- instance.totalPrice, // Computed getter
180
- currentState.items.length // Number of items
181
- ] // Only re-render when total price or item count changes
182
- });
183
- ```
184
-
185
- **Compare with previous state:**
186
- ```tsx
187
- const [state, chatBloc] = useBloc(ChatBloc, {
188
- selector: (currentState, previousState) => [
189
- currentState.messages.length > (previousState?.messages.length || 0) ? 'new-message' : 'no-change'
190
- ] // Only re-render when new messages are added, not when existing messages change
191
- });
192
- ```
193
-
194
- ## API Reference
195
-
196
- ### useBloc Hook
197
-
198
- ```typescript
199
- function useBloc<B extends BlocConstructor<BlocGeneric>>(
200
- bloc: B,
201
- options?: BlocHookOptions<InstanceType<B>>
202
- ): [BlocState<InstanceType<B>>, InstanceType<B>]
203
- ```
204
-
205
- #### Options
206
-
207
- - `id?: string` - Custom identifier for the bloc instance
208
- - `props?: InferPropsFromGeneric<B>` - Props to pass to the bloc
209
- - `onMount?: (bloc: B) => void` - Callback function invoked when the react component (the consumer) is connected to the bloc instance
210
- - `selector?: (currentState: BlocState<InstanceType<B>>, previousState: BlocState<InstanceType<B>> | undefined, instance: InstanceType<B>) => unknown[]` - Function to select dependencies for re-renders
211
-
212
- ## Best Practices
213
-
214
- 1. **Use Isolated Blocs**: When you need component-specific state, use isolated blocs:
215
- ```tsx
216
- class MyIsolatedBloc extends BlocBase {
217
- static isolated = true;
218
- // ... rest of your bloc implementation
219
- }
220
- ```
221
-
222
- 2. **Use Custom Identifiers**: When you need multiple independent instances of the same Bloc type, use custom identifiers to manage different state contexts:
223
- ```tsx
224
- // In a chat application with multiple chat rooms
225
- function ChatRoom({ roomId }: { roomId: string }) {
226
- const [state, chatBloc] = useBloc(ChatBloc, {
227
- id: `chat-${roomId}`, // Each room gets its own instance
228
- props: { roomId }
229
- });
230
-
231
- return (
232
- <div>
233
- <h2>Room: {roomId}</h2>
234
- {state.messages.map(msg => (
235
- <Message key={msg.id} message={msg} />
236
- ))}
237
- </div>
238
- );
239
- }
240
-
241
- // Usage:
242
- function ChatApp() {
243
- return (
244
- <div>
245
- <ChatRoom roomId="general" />
246
- <ChatRoom roomId="support" />
247
- </div>
248
- );
249
- }
250
- ```
251
-
252
- 3. **Choose the Right Dependency Strategy**:
253
- - **Use automatic tracking** (default) for most cases - it's efficient and requires no setup
254
- - **Use custom selectors** when you need complex logic, computed comparisons, or want to ignore certain property changes
255
- - **Avoid custom selectors** for simple property access - automatic tracking is more efficient
256
-
257
- 4. **Type Safety**: Take advantage of TypeScript's type inference for better development experience and catch errors early.
258
-
259
- ## Contributing
260
-
261
- Contributions are welcome! Please feel free to submit a Pull Request.
262
-
263
- ## License
264
-
265
- MIT