@oimdb/react 1.1.0 → 1.2.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 +338 -44
- package/dist/index.cjs +206 -152
- package/dist/index.d.cts +17 -28
- package/dist/index.d.ts +17 -28
- package/dist/index.js +199 -149
- package/package.json +25 -7
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ React integration for OIMDB - Hooks for selection and subscription with reactive
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **Reactive Integration**: Hooks work with `OIMReactiveCollection` and
|
|
11
|
+
- **Reactive Integration**: Hooks work with `OIMReactiveCollection` and reactive indexes from `@oimdb/core`
|
|
12
|
+
- **Index Type Support**: Separate hooks for SetBased indexes (return `Set<TPk>`) and ArrayBased indexes (return `TPk[]`)
|
|
12
13
|
- **Automatic Subscription**: Uses `useSyncExternalStore` for optimal React 18+ performance
|
|
13
14
|
- **Event Coalescing**: Leverages OIMDB's built-in event coalescing for efficient updates
|
|
14
15
|
- **Type Safety**: Full TypeScript support with advanced generic type inference
|
|
@@ -26,16 +27,28 @@ npm install @oimdb/react @oimdb/core
|
|
|
26
27
|
### Basic Setup
|
|
27
28
|
|
|
28
29
|
```typescript
|
|
29
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
OIMEventQueue,
|
|
32
|
+
OIMRICollection,
|
|
33
|
+
OIMReactiveIndexManualSetBased,
|
|
34
|
+
OIMReactiveIndexManualArrayBased
|
|
35
|
+
} from '@oimdb/core';
|
|
30
36
|
import {
|
|
31
37
|
useSelectEntitiesByPks,
|
|
32
|
-
|
|
38
|
+
useSelectEntitiesByIndexKeySetBased,
|
|
39
|
+
useSelectEntitiesByIndexKeyArrayBased,
|
|
33
40
|
useSelectEntityByPk
|
|
34
41
|
} from '@oimdb/react';
|
|
35
42
|
|
|
36
43
|
// Create event queue and reactive collections
|
|
37
44
|
const queue = new OIMEventQueue();
|
|
38
|
-
|
|
45
|
+
|
|
46
|
+
// Choose index type based on your needs:
|
|
47
|
+
// - SetBased: for frequent add/remove operations, order doesn't matter
|
|
48
|
+
// - ArrayBased: for full replacements or when order/sorting matters
|
|
49
|
+
const userTeamIndex = new OIMReactiveIndexManualSetBased<string, string>(queue);
|
|
50
|
+
const deckCardsIndex = new OIMReactiveIndexManualArrayBased<string, string>(queue);
|
|
51
|
+
|
|
39
52
|
const usersCollection = new OIMRICollection(queue, {
|
|
40
53
|
collectionOpts: { selectPk: (user: User) => user.id },
|
|
41
54
|
indexes: { byTeam: userTeamIndex },
|
|
@@ -79,14 +92,27 @@ function UserList({ userIds }: { userIds: string[] }) {
|
|
|
79
92
|
|
|
80
93
|
### Index-based Selection
|
|
81
94
|
|
|
95
|
+
OIMDB provides separate hooks for SetBased and ArrayBased indexes:
|
|
96
|
+
|
|
97
|
+
#### SetBased Indexes (returns Set)
|
|
98
|
+
|
|
82
99
|
```typescript
|
|
100
|
+
import { useSelectEntitiesByIndexKeySetBased, useSelectPksByIndexKeySetBased } from '@oimdb/react';
|
|
101
|
+
|
|
83
102
|
function TeamMembers({ teamId }: { teamId: string }) {
|
|
84
|
-
|
|
103
|
+
// For SetBased indexes, use SetBased hooks
|
|
104
|
+
const teamUsers = useSelectEntitiesByIndexKeySetBased(
|
|
85
105
|
usersCollection,
|
|
86
|
-
usersCollection.indexes.byTeam,
|
|
106
|
+
usersCollection.indexes.byTeam, // OIMReactiveIndexManualSetBased
|
|
87
107
|
teamId
|
|
88
108
|
);
|
|
89
109
|
|
|
110
|
+
// Or get just the PKs as Set
|
|
111
|
+
const teamUserIds = useSelectPksByIndexKeySetBased(
|
|
112
|
+
usersCollection.indexes.byTeam,
|
|
113
|
+
teamId
|
|
114
|
+
); // Returns Set<string>
|
|
115
|
+
|
|
90
116
|
return (
|
|
91
117
|
<div>
|
|
92
118
|
{teamUsers.map((user, index) => (
|
|
@@ -99,6 +125,37 @@ function TeamMembers({ teamId }: { teamId: string }) {
|
|
|
99
125
|
}
|
|
100
126
|
```
|
|
101
127
|
|
|
128
|
+
#### ArrayBased Indexes (returns Array)
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { useSelectEntitiesByIndexKeyArrayBased, useSelectPksByIndexKeyArrayBased } from '@oimdb/react';
|
|
132
|
+
|
|
133
|
+
function DeckCards({ deckId }: { deckId: string }) {
|
|
134
|
+
// For ArrayBased indexes, use ArrayBased hooks
|
|
135
|
+
const cards = useSelectEntitiesByIndexKeyArrayBased(
|
|
136
|
+
cardsCollection,
|
|
137
|
+
cardsCollection.indexes.byDeck, // OIMReactiveIndexManualArrayBased
|
|
138
|
+
deckId
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Or get just the PKs as Array (preserves order)
|
|
142
|
+
const cardIds = useSelectPksByIndexKeyArrayBased(
|
|
143
|
+
cardsCollection.indexes.byDeck,
|
|
144
|
+
deckId
|
|
145
|
+
); // Returns string[] (preserves order/sorting)
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<div>
|
|
149
|
+
{cards.map((card, index) => (
|
|
150
|
+
<div key={card?.id || index}>
|
|
151
|
+
{card ? `${index + 1}. ${card.name}` : 'Loading...'}
|
|
152
|
+
</div>
|
|
153
|
+
))}
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
102
159
|
## React Context Integration
|
|
103
160
|
|
|
104
161
|
For applications with multiple collections, use the React Context pattern for centralized management:
|
|
@@ -108,8 +165,7 @@ For applications with multiple collections, use the React Context pattern for ce
|
|
|
108
165
|
```typescript
|
|
109
166
|
import {
|
|
110
167
|
OIMRICollectionsProvider,
|
|
111
|
-
useOIMCollectionsContext
|
|
112
|
-
StrictCollectionsDictionary
|
|
168
|
+
useOIMCollectionsContext
|
|
113
169
|
} from '@oimdb/react';
|
|
114
170
|
|
|
115
171
|
interface User {
|
|
@@ -126,7 +182,8 @@ interface Team {
|
|
|
126
182
|
function createCollections() {
|
|
127
183
|
const queue = new OIMEventQueue();
|
|
128
184
|
|
|
129
|
-
|
|
185
|
+
// Use SetBased for frequent add/remove operations
|
|
186
|
+
const userTeamIndex = new OIMReactiveIndexManualSetBased<string, string>(queue);
|
|
130
187
|
const usersCollection = new OIMRICollection(queue, {
|
|
131
188
|
collectionOpts: { selectPk: (user: User) => user.id },
|
|
132
189
|
indexes: { byTeam: userTeamIndex },
|
|
@@ -140,9 +197,156 @@ function createCollections() {
|
|
|
140
197
|
return { users: usersCollection, teams: teamsCollection } as const;
|
|
141
198
|
}
|
|
142
199
|
|
|
143
|
-
type AppCollections =
|
|
200
|
+
type AppCollections = ReturnType<typeof createCollections>;
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## TypeScript Typing Strategies
|
|
204
|
+
|
|
205
|
+
For maximum type safety, you should properly type your collections dictionary. There are two main approaches, similar to how Redux handles state typing:
|
|
206
|
+
|
|
207
|
+
### Approach 1: Using `typeof` (Recommended for Simple Cases)
|
|
208
|
+
|
|
209
|
+
The simplest approach is to use TypeScript's `typeof` operator to infer types from your collection instances:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { OIMEventQueue, OIMRICollection, OIMReactiveIndexManual } from '@oimdb/core';
|
|
213
|
+
|
|
214
|
+
interface User {
|
|
215
|
+
id: string;
|
|
216
|
+
name: string;
|
|
217
|
+
teamId: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
interface Team {
|
|
221
|
+
id: string;
|
|
222
|
+
name: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Create collections
|
|
226
|
+
const queue = new OIMEventQueue();
|
|
227
|
+
const userTeamIndex = new OIMReactiveIndexManualSetBased<string, string>(queue);
|
|
228
|
+
const usersCollection = new OIMRICollection(queue, {
|
|
229
|
+
collectionOpts: { selectPk: (user: User) => user.id },
|
|
230
|
+
indexes: { byTeam: userTeamIndex },
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const teamsCollection = new OIMRICollection(queue, {
|
|
234
|
+
collectionOpts: { selectPk: (team: Team) => team.id },
|
|
235
|
+
indexes: {},
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Infer types using typeof
|
|
239
|
+
const collections = {
|
|
240
|
+
users: usersCollection,
|
|
241
|
+
teams: teamsCollection,
|
|
242
|
+
} as const;
|
|
243
|
+
|
|
244
|
+
// Extract the type
|
|
245
|
+
type AppCollections = typeof collections;
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Usage:**
|
|
249
|
+
```typescript
|
|
250
|
+
function MyComponent() {
|
|
251
|
+
const { users, teams } = useOIMCollectionsContext<AppCollections>();
|
|
252
|
+
// users and teams are fully typed with all their generics preserved
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Approach 2: Creating Explicit Types (Recommended for Complex Projects)
|
|
257
|
+
|
|
258
|
+
For larger applications or when you need more control, create explicit type definitions similar to Redux's approach:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import {
|
|
262
|
+
OIMEventQueue,
|
|
263
|
+
OIMRICollection,
|
|
264
|
+
OIMReactiveIndexManualSetBased
|
|
265
|
+
} from '@oimdb/core';
|
|
266
|
+
import type {
|
|
267
|
+
TOIMPk,
|
|
268
|
+
OIMIndexSetBased,
|
|
269
|
+
OIMReactiveIndexSetBased
|
|
270
|
+
} from '@oimdb/core';
|
|
271
|
+
|
|
272
|
+
interface User {
|
|
273
|
+
id: string;
|
|
274
|
+
name: string;
|
|
275
|
+
teamId: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
interface Team {
|
|
279
|
+
id: string;
|
|
280
|
+
name: string;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Define your collection types explicitly
|
|
284
|
+
type UserCollection = OIMRICollection<
|
|
285
|
+
User,
|
|
286
|
+
string,
|
|
287
|
+
'byTeam',
|
|
288
|
+
string,
|
|
289
|
+
OIMIndexSetBased<string, string>,
|
|
290
|
+
OIMReactiveIndexSetBased<string, string, OIMIndexSetBased<string, string>>
|
|
291
|
+
>;
|
|
292
|
+
|
|
293
|
+
type TeamCollection = OIMRICollection<
|
|
294
|
+
Team,
|
|
295
|
+
string,
|
|
296
|
+
never,
|
|
297
|
+
never,
|
|
298
|
+
OIMIndexSetBased<never, never>,
|
|
299
|
+
OIMReactiveIndexSetBased<never, never, OIMIndexSetBased<never, never>>
|
|
300
|
+
>;
|
|
301
|
+
|
|
302
|
+
// Define your collections dictionary type
|
|
303
|
+
interface AppCollections {
|
|
304
|
+
users: UserCollection;
|
|
305
|
+
teams: TeamCollection;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Factory function that returns properly typed collections
|
|
309
|
+
function createCollections(): AppCollections {
|
|
310
|
+
const queue = new OIMEventQueue();
|
|
311
|
+
const userTeamIndex = new OIMReactiveIndexManualSetBased<string, string>(queue);
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
users: new OIMRICollection(queue, {
|
|
315
|
+
collectionOpts: { selectPk: (user: User) => user.id },
|
|
316
|
+
indexes: { byTeam: userTeamIndex },
|
|
317
|
+
}) as UserCollection,
|
|
318
|
+
|
|
319
|
+
teams: new OIMRICollection(queue, {
|
|
320
|
+
collectionOpts: { selectPk: (team: Team) => team.id },
|
|
321
|
+
indexes: {},
|
|
322
|
+
}) as TeamCollection,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Usage:**
|
|
328
|
+
```typescript
|
|
329
|
+
function MyComponent() {
|
|
330
|
+
const { users, teams } = useOIMCollectionsContext<AppCollections>();
|
|
331
|
+
// Full type safety with explicit types
|
|
332
|
+
}
|
|
144
333
|
```
|
|
145
334
|
|
|
335
|
+
### When to Use Each Approach
|
|
336
|
+
|
|
337
|
+
- **Use `typeof`** when:
|
|
338
|
+
- You have simple collection setups
|
|
339
|
+
- You want TypeScript to infer everything automatically
|
|
340
|
+
- You prefer less boilerplate
|
|
341
|
+
- Your collections are created in one place
|
|
342
|
+
|
|
343
|
+
- **Use explicit types** when:
|
|
344
|
+
- You need to share types across multiple files
|
|
345
|
+
- You want to document your data structure explicitly
|
|
346
|
+
- You're building a library or shared module
|
|
347
|
+
- You need to ensure type consistency across your application
|
|
348
|
+
- You prefer Redux-style explicit typing patterns
|
|
349
|
+
|
|
146
350
|
### Provider Setup
|
|
147
351
|
|
|
148
352
|
```typescript
|
|
@@ -165,9 +369,10 @@ function UserDashboard() {
|
|
|
165
369
|
|
|
166
370
|
// Use collections with hooks
|
|
167
371
|
const allUsers = useSelectEntitiesByPks(users, []);
|
|
168
|
-
|
|
372
|
+
// Use appropriate hook based on index type
|
|
373
|
+
const teamMembers = useSelectEntitiesByIndexKeySetBased(
|
|
169
374
|
users,
|
|
170
|
-
users.indexes.byTeam,
|
|
375
|
+
users.indexes.byTeam, // SetBased index
|
|
171
376
|
'team1'
|
|
172
377
|
);
|
|
173
378
|
|
|
@@ -227,51 +432,105 @@ Subscribes to multiple entities from a reactive collection.
|
|
|
227
432
|
**Returns:**
|
|
228
433
|
- `(TEntity | undefined)[]` - Array of entities (undefined for missing entities)
|
|
229
434
|
|
|
230
|
-
###
|
|
435
|
+
### Index-based Selection Hooks
|
|
436
|
+
|
|
437
|
+
OIMDB provides separate hooks for SetBased and ArrayBased indexes to ensure type safety and correct return types.
|
|
438
|
+
|
|
439
|
+
#### SetBased Index Hooks
|
|
231
440
|
|
|
232
|
-
|
|
441
|
+
##### `useSelectEntitiesByIndexKeySetBased(reactiveCollection, reactiveIndex, key)`
|
|
442
|
+
|
|
443
|
+
Subscribes to entities indexed by a specific key from a SetBased index.
|
|
233
444
|
|
|
234
445
|
**Parameters:**
|
|
235
446
|
- `reactiveCollection: OIMReactiveCollection<TEntity, TPk>` - Reactive collection instance
|
|
236
|
-
- `reactiveIndex:
|
|
447
|
+
- `reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>` - SetBased reactive index instance
|
|
237
448
|
- `key: TKey` - Index key to query
|
|
238
449
|
|
|
239
450
|
**Returns:**
|
|
240
451
|
- `(TEntity | undefined)[]` - Array of entities for the given index key
|
|
241
452
|
|
|
242
|
-
|
|
453
|
+
##### `useSelectEntitiesByIndexKeysSetBased(reactiveCollection, reactiveIndex, keys)`
|
|
243
454
|
|
|
244
|
-
Subscribes to entities indexed by multiple keys.
|
|
455
|
+
Subscribes to entities indexed by multiple keys from a SetBased index.
|
|
245
456
|
|
|
246
457
|
**Parameters:**
|
|
247
458
|
- `reactiveCollection: OIMReactiveCollection<TEntity, TPk>` - Reactive collection instance
|
|
248
|
-
- `reactiveIndex:
|
|
459
|
+
- `reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>` - SetBased reactive index instance
|
|
249
460
|
- `keys: readonly TKey[]` - Array of index keys to query
|
|
250
461
|
|
|
251
462
|
**Returns:**
|
|
252
463
|
- `(TEntity | undefined)[]` - Array of entities for the given index keys
|
|
253
464
|
|
|
254
|
-
|
|
465
|
+
##### `useSelectPksByIndexKeySetBased(reactiveIndex, key)`
|
|
466
|
+
|
|
467
|
+
Subscribes to primary keys indexed by a specific key from a SetBased index.
|
|
468
|
+
|
|
469
|
+
**Parameters:**
|
|
470
|
+
- `reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>` - SetBased reactive index instance
|
|
471
|
+
- `key: TKey` - Index key to query
|
|
472
|
+
|
|
473
|
+
**Returns:**
|
|
474
|
+
- `Set<TPk>` - Set of primary keys for the given index key
|
|
475
|
+
|
|
476
|
+
##### `useSelectPksByIndexKeysSetBased(reactiveIndex, keys)`
|
|
477
|
+
|
|
478
|
+
Subscribes to primary keys indexed by multiple keys from a SetBased index.
|
|
479
|
+
|
|
480
|
+
**Parameters:**
|
|
481
|
+
- `reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>` - SetBased reactive index instance
|
|
482
|
+
- `keys: readonly TKey[]` - Array of index keys to query
|
|
483
|
+
|
|
484
|
+
**Returns:**
|
|
485
|
+
- `Map<TKey, Set<TPk>>` - Map of index keys to their corresponding primary key Sets
|
|
486
|
+
|
|
487
|
+
#### ArrayBased Index Hooks
|
|
255
488
|
|
|
256
|
-
|
|
489
|
+
##### `useSelectEntitiesByIndexKeyArrayBased(reactiveCollection, reactiveIndex, key)`
|
|
490
|
+
|
|
491
|
+
Subscribes to entities indexed by a specific key from an ArrayBased index.
|
|
257
492
|
|
|
258
493
|
**Parameters:**
|
|
259
|
-
- `
|
|
494
|
+
- `reactiveCollection: OIMReactiveCollection<TEntity, TPk>` - Reactive collection instance
|
|
495
|
+
- `reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>` - ArrayBased reactive index instance
|
|
260
496
|
- `key: TKey` - Index key to query
|
|
261
497
|
|
|
262
498
|
**Returns:**
|
|
263
|
-
- `
|
|
499
|
+
- `(TEntity | undefined)[]` - Array of entities for the given index key (preserves order)
|
|
264
500
|
|
|
265
|
-
|
|
501
|
+
##### `useSelectEntitiesByIndexKeysArrayBased(reactiveCollection, reactiveIndex, keys)`
|
|
266
502
|
|
|
267
|
-
Subscribes to
|
|
503
|
+
Subscribes to entities indexed by multiple keys from an ArrayBased index.
|
|
268
504
|
|
|
269
505
|
**Parameters:**
|
|
270
|
-
- `
|
|
506
|
+
- `reactiveCollection: OIMReactiveCollection<TEntity, TPk>` - Reactive collection instance
|
|
507
|
+
- `reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>` - ArrayBased reactive index instance
|
|
271
508
|
- `keys: readonly TKey[]` - Array of index keys to query
|
|
272
509
|
|
|
273
510
|
**Returns:**
|
|
274
|
-
- `
|
|
511
|
+
- `(TEntity | undefined)[]` - Array of entities for the given index keys (preserves order)
|
|
512
|
+
|
|
513
|
+
##### `useSelectPksByIndexKeyArrayBased(reactiveIndex, key)`
|
|
514
|
+
|
|
515
|
+
Subscribes to primary keys indexed by a specific key from an ArrayBased index.
|
|
516
|
+
|
|
517
|
+
**Parameters:**
|
|
518
|
+
- `reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>` - ArrayBased reactive index instance
|
|
519
|
+
- `key: TKey` - Index key to query
|
|
520
|
+
|
|
521
|
+
**Returns:**
|
|
522
|
+
- `TPk[]` - Array of primary keys for the given index key (preserves order/sorting)
|
|
523
|
+
|
|
524
|
+
##### `useSelectPksByIndexKeysArrayBased(reactiveIndex, keys)`
|
|
525
|
+
|
|
526
|
+
Subscribes to primary keys indexed by multiple keys from an ArrayBased index.
|
|
527
|
+
|
|
528
|
+
**Parameters:**
|
|
529
|
+
- `reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>` - ArrayBased reactive index instance
|
|
530
|
+
- `keys: readonly TKey[]` - Array of index keys to query
|
|
531
|
+
|
|
532
|
+
**Returns:**
|
|
533
|
+
- `Map<TKey, TPk[]>` - Map of index keys to their corresponding primary key arrays (preserves order)
|
|
275
534
|
|
|
276
535
|
## Context API Reference
|
|
277
536
|
|
|
@@ -306,17 +565,9 @@ Creates a custom collections context with specific typing.
|
|
|
306
565
|
|
|
307
566
|
### Type Utilities
|
|
308
567
|
|
|
309
|
-
#### `StrictCollectionsDictionary<T>`
|
|
310
|
-
|
|
311
|
-
Ensures collections dictionary maintains exact types.
|
|
312
|
-
|
|
313
568
|
#### `CollectionsDictionary`
|
|
314
569
|
|
|
315
|
-
Base type for any collections dictionary.
|
|
316
|
-
|
|
317
|
-
#### `ExtractEntityType<T>`, `ExtractPkType<T>`, etc.
|
|
318
|
-
|
|
319
|
-
Type utilities for extracting specific types from collections.
|
|
570
|
+
Base type for any collections dictionary. Use `typeof` to extract types from your collection instances, or define explicit types using `OIMRICollection` generics.
|
|
320
571
|
|
|
321
572
|
## Architecture
|
|
322
573
|
|
|
@@ -327,7 +578,19 @@ The hooks work directly with OIMDB reactive objects:
|
|
|
327
578
|
```typescript
|
|
328
579
|
// Use reactive collections and indexes directly
|
|
329
580
|
const user = useSelectEntityByPk(reactiveCollection, 'user123');
|
|
330
|
-
|
|
581
|
+
|
|
582
|
+
// Use appropriate hook based on index type
|
|
583
|
+
const posts = useSelectEntitiesByIndexKeySetBased(
|
|
584
|
+
reactiveCollection,
|
|
585
|
+
reactiveIndexSetBased, // SetBased index
|
|
586
|
+
'tech'
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
const orderedCards = useSelectEntitiesByIndexKeyArrayBased(
|
|
590
|
+
reactiveCollection,
|
|
591
|
+
reactiveIndexArrayBased, // ArrayBased index
|
|
592
|
+
'deck1'
|
|
593
|
+
);
|
|
331
594
|
```
|
|
332
595
|
|
|
333
596
|
### Event Subscription
|
|
@@ -339,6 +602,15 @@ Hooks automatically subscribe to OIMDB reactive events using `useSyncExternalSto
|
|
|
339
602
|
- **Optimized subscriptions**: Subscribe only to specific keys for efficient updates
|
|
340
603
|
- **Automatic cleanup**: Unsubscribe when component unmounts
|
|
341
604
|
|
|
605
|
+
### Index Type Selection
|
|
606
|
+
|
|
607
|
+
When working with indexes, choose the appropriate hook based on your index type:
|
|
608
|
+
|
|
609
|
+
- **SetBased indexes** (`OIMReactiveIndexManualSetBased`): Use `*SetBased` hooks (e.g., `useSelectPksByIndexKeySetBased`) - returns `Set<TPk>`
|
|
610
|
+
- **ArrayBased indexes** (`OIMReactiveIndexManualArrayBased`): Use `*ArrayBased` hooks (e.g., `useSelectPksByIndexKeyArrayBased`) - returns `TPk[]` (preserves order)
|
|
611
|
+
|
|
612
|
+
This ensures type safety and correct return types. TypeScript will enforce the correct hook usage based on your index type.
|
|
613
|
+
|
|
342
614
|
### Performance
|
|
343
615
|
|
|
344
616
|
- **React 18+ Integration**: Uses `useSyncExternalStore` for optimal performance
|
|
@@ -353,8 +625,18 @@ Hooks automatically subscribe to OIMDB reactive events using `useSyncExternalSto
|
|
|
353
625
|
|
|
354
626
|
```typescript
|
|
355
627
|
import React from 'react';
|
|
356
|
-
import {
|
|
357
|
-
|
|
628
|
+
import {
|
|
629
|
+
OIMEventQueue,
|
|
630
|
+
OIMRICollection,
|
|
631
|
+
OIMReactiveIndexManualSetBased,
|
|
632
|
+
OIMReactiveIndexManualArrayBased
|
|
633
|
+
} from '@oimdb/core';
|
|
634
|
+
import {
|
|
635
|
+
useSelectEntityByPk,
|
|
636
|
+
useSelectEntitiesByPks,
|
|
637
|
+
useSelectEntitiesByIndexKeySetBased,
|
|
638
|
+
useSelectEntitiesByIndexKeyArrayBased
|
|
639
|
+
} from '@oimdb/react';
|
|
358
640
|
|
|
359
641
|
interface User {
|
|
360
642
|
id: string;
|
|
@@ -366,7 +648,8 @@ interface User {
|
|
|
366
648
|
// Setup
|
|
367
649
|
function createUserCollection() {
|
|
368
650
|
const queue = new OIMEventQueue();
|
|
369
|
-
|
|
651
|
+
// Use SetBased for frequent add/remove operations
|
|
652
|
+
const teamIndex = new OIMReactiveIndexManualSetBased<string, string>(queue);
|
|
370
653
|
|
|
371
654
|
return new OIMRICollection(queue, {
|
|
372
655
|
collectionOpts: { selectPk: (user: User) => user.id },
|
|
@@ -386,9 +669,10 @@ function UserProfile({ userId }: { userId: string }) {
|
|
|
386
669
|
}
|
|
387
670
|
|
|
388
671
|
function TeamDashboard({ teamId }: { teamId: string }) {
|
|
389
|
-
|
|
672
|
+
// Use SetBased hook for SetBased index
|
|
673
|
+
const teamMembers = useSelectEntitiesByIndexKeySetBased(
|
|
390
674
|
usersCollection,
|
|
391
|
-
usersCollection.indexes.byTeam,
|
|
675
|
+
usersCollection.indexes.byTeam, // OIMReactiveIndexManualSetBased
|
|
392
676
|
teamId
|
|
393
677
|
);
|
|
394
678
|
|
|
@@ -396,7 +680,7 @@ function TeamDashboard({ teamId }: { teamId: string }) {
|
|
|
396
680
|
<div>
|
|
397
681
|
<h3>Team Members ({teamMembers.length})</h3>
|
|
398
682
|
{teamMembers.map(user => (
|
|
399
|
-
<div key={user
|
|
683
|
+
<div key={user?.id}>{user?.name}</div>
|
|
400
684
|
))}
|
|
401
685
|
</div>
|
|
402
686
|
);
|
|
@@ -444,10 +728,20 @@ const user = useEntity(userStorage, 'user123');
|
|
|
444
728
|
const users = useEntities(userStorage, userIds);
|
|
445
729
|
const posts = useIndex(postStorage, categoryIndex, 'tech');
|
|
446
730
|
|
|
447
|
-
// v1.x - Reactive collections
|
|
731
|
+
// v1.x - Reactive collections with typed indexes
|
|
448
732
|
const user = useSelectEntityByPk(reactiveCollection, 'user123');
|
|
449
733
|
const users = useSelectEntitiesByPks(reactiveCollection, userIds);
|
|
450
|
-
|
|
734
|
+
// Use appropriate hook based on index type
|
|
735
|
+
const posts = useSelectEntitiesByIndexKeySetBased(
|
|
736
|
+
reactiveCollection,
|
|
737
|
+
reactiveIndexSetBased,
|
|
738
|
+
'tech'
|
|
739
|
+
);
|
|
740
|
+
const orderedItems = useSelectEntitiesByIndexKeyArrayBased(
|
|
741
|
+
reactiveCollection,
|
|
742
|
+
reactiveIndexArrayBased,
|
|
743
|
+
'category1'
|
|
744
|
+
);
|
|
451
745
|
```
|
|
452
746
|
|
|
453
747
|
### Collection Creation
|