0
# Core Composition Hooks
1
2
The Core Composition Hooks provide essential Vue composition utilities for component relationships, slot management, and performance optimization. These hooks are built on top of the adapter system and work seamlessly across Vue 2 and Vue 3.
3
4
## Capabilities
5
6
### Instance Slots Hook
7
8
Hook for managing component slots with cross-framework compatibility and reactive updates.
9
10
```typescript { .api }
11
/**
12
* Create instance slots manager with cross-framework compatibility
13
* @param hooks - Adapter hooks system
14
* @returns Instance slots manager
15
*/
16
function useInstanceSlots(hooks: AdapterHooks): any;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { useInstanceSlots, hooks } from "@opentiny/vue-common";
23
24
export default {
25
setup(props, context) {
26
const instanceSlots = useInstanceSlots(hooks);
27
28
// Access slots reactively
29
const hasDefaultSlot = hooks.computed(() => {
30
return !!instanceSlots.default;
31
});
32
33
const hasHeaderSlot = hooks.computed(() => {
34
return !!instanceSlots.header;
35
});
36
37
return {
38
instanceSlots,
39
hasDefaultSlot,
40
hasHeaderSlot
41
};
42
},
43
template: `
44
<div class="component">
45
<header v-if="hasHeaderSlot">
46
<slot name="header" />
47
</header>
48
<main v-if="hasDefaultSlot">
49
<slot />
50
</main>
51
</div>
52
`
53
};
54
```
55
56
### Component Relation Hook
57
58
Hook for managing parent-child component relationships and communication patterns.
59
60
```typescript { .api }
61
/**
62
* Create component relation manager for parent-child communication
63
* @param hooks - Adapter hooks system
64
* @returns Component relation manager
65
*/
66
function useRelation(hooks: AdapterHooks): any;
67
```
68
69
**Usage Examples:**
70
71
```typescript
72
import { useRelation, hooks } from "@opentiny/vue-common";
73
74
// Parent component
75
export default {
76
name: 'ParentComponent',
77
setup() {
78
const relation = useRelation(hooks);
79
80
const children = hooks.ref([]);
81
82
const registerChild = (child) => {
83
children.value.push(child);
84
};
85
86
const unregisterChild = (child) => {
87
const index = children.value.indexOf(child);
88
if (index > -1) {
89
children.value.splice(index, 1);
90
}
91
};
92
93
// Provide registration methods to children
94
hooks.provide('parentRelation', {
95
registerChild,
96
unregisterChild
97
});
98
99
return {
100
children,
101
relation
102
};
103
}
104
};
105
106
// Child component
107
export default {
108
name: 'ChildComponent',
109
setup() {
110
const relation = useRelation(hooks);
111
const parentRelation = hooks.inject('parentRelation', null);
112
113
const instance = hooks.getCurrentInstance();
114
115
hooks.onMounted(() => {
116
if (parentRelation) {
117
parentRelation.registerChild(instance);
118
}
119
});
120
121
hooks.onBeforeUnmount(() => {
122
if (parentRelation) {
123
parentRelation.unregisterChild(instance);
124
}
125
});
126
127
return {
128
relation
129
};
130
}
131
};
132
```
133
134
### Deferred Rendering Hook
135
136
Performance optimization hook for progressive component rendering with frame-based control.
137
138
```typescript { .api }
139
/**
140
* Create deferred rendering controller for performance optimization
141
* @param maxCount - Maximum frame count before stopping (default: 100)
142
* @returns Deferred rendering controller
143
*/
144
function useDefer(maxCount?: number): {
145
/** Check if rendering should be deferred for given frame number */
146
defer(n: number): boolean;
147
/** Reset frame counter to start over */
148
reset(): void;
149
/** Cancel animation frames and stop counting */
150
cancel(): void;
151
};
152
```
153
154
**Usage Examples:**
155
156
```typescript
157
import { useDefer, hooks } from "@opentiny/vue-common";
158
159
export default {
160
setup() {
161
const deferrer = useDefer(50); // Limit to 50 frames
162
163
// Progressive rendering of list items
164
const items = hooks.ref(Array.from({ length: 1000 }, (_, i) => `Item ${i}`));
165
166
const visibleItems = hooks.computed(() => {
167
return items.value.filter((_, index) => {
168
// Show first 10 items immediately
169
if (index < 10) return true;
170
171
// Progressive reveal based on frame count
172
const frameThreshold = Math.floor(index / 10) + 1;
173
return deferrer.defer(frameThreshold);
174
});
175
});
176
177
// Reset deferred rendering on data change
178
hooks.watch(items, () => {
179
deferrer.reset();
180
});
181
182
return {
183
visibleItems,
184
deferrer
185
};
186
},
187
template: `
188
<div class="large-list">
189
<div v-for="item in visibleItems" :key="item" class="list-item">
190
{{ item }}
191
</div>
192
</div>
193
`
194
};
195
```
196
197
## Advanced Usage Patterns
198
199
### Slot-Based Component Composition
200
201
Using instance slots for flexible component composition.
202
203
```typescript
204
import { useInstanceSlots, hooks } from "@opentiny/vue-common";
205
206
export default {
207
setup() {
208
const slots = useInstanceSlots(hooks);
209
210
// Dynamic slot analysis
211
const slotAnalysis = hooks.computed(() => {
212
const analysis = {
213
hasContent: false,
214
hasActions: false,
215
hasCustom: false,
216
customSlots: []
217
};
218
219
if (slots.default) analysis.hasContent = true;
220
if (slots.actions) analysis.hasActions = true;
221
222
// Find custom slots
223
Object.keys(slots).forEach(slotName => {
224
if (!['default', 'actions'].includes(slotName)) {
225
analysis.hasCustom = true;
226
analysis.customSlots.push(slotName);
227
}
228
});
229
230
return analysis;
231
});
232
233
return {
234
slots,
235
slotAnalysis
236
};
237
},
238
template: `
239
<div class="flexible-component">
240
<div v-if="slotAnalysis.hasContent" class="content">
241
<slot />
242
</div>
243
244
<div v-for="customSlot in slotAnalysis.customSlots"
245
:key="customSlot"
246
:class="'custom-' + customSlot">
247
<slot :name="customSlot" />
248
</div>
249
250
<div v-if="slotAnalysis.hasActions" class="actions">
251
<slot name="actions" />
252
</div>
253
</div>
254
`
255
};
256
```
257
258
### Parent-Child Communication System
259
260
Building a comprehensive parent-child communication system.
261
262
```typescript
263
import { useRelation, hooks } from "@opentiny/vue-common";
264
265
// Communication mixin
266
const useParentChildComm = () => {
267
const relation = useRelation(hooks);
268
269
// For parent components
270
const createParentComm = () => {
271
const children = hooks.ref(new Map());
272
273
const addChild = (id, child) => {
274
children.value.set(id, child);
275
};
276
277
const removeChild = (id) => {
278
children.value.delete(id);
279
};
280
281
const broadcastToChildren = (message, data) => {
282
children.value.forEach(child => {
283
if (child.receiveMessage) {
284
child.receiveMessage(message, data);
285
}
286
});
287
};
288
289
hooks.provide('parentComm', {
290
addChild,
291
removeChild,
292
broadcastToChildren
293
});
294
295
return {
296
children,
297
broadcastToChildren
298
};
299
};
300
301
// For child components
302
const createChildComm = (childId) => {
303
const parentComm = hooks.inject('parentComm', null);
304
const messages = hooks.ref([]);
305
306
const receiveMessage = (message, data) => {
307
messages.value.push({ message, data, timestamp: Date.now() });
308
};
309
310
const sendToParent = (message, data) => {
311
if (parentComm) {
312
parentComm.receiveFromChild?.(childId, message, data);
313
}
314
};
315
316
hooks.onMounted(() => {
317
if (parentComm) {
318
parentComm.addChild(childId, { receiveMessage });
319
}
320
});
321
322
hooks.onBeforeUnmount(() => {
323
if (parentComm) {
324
parentComm.removeChild(childId);
325
}
326
});
327
328
return {
329
messages,
330
receiveMessage,
331
sendToParent
332
};
333
};
334
335
return {
336
createParentComm,
337
createChildComm
338
};
339
};
340
```
341
342
### Performance-Optimized List Rendering
343
344
Using deferred rendering for large datasets.
345
346
```typescript
347
import { useDefer, hooks } from "@opentiny/vue-common";
348
349
export default {
350
props: {
351
items: Array,
352
chunkSize: {
353
type: Number,
354
default: 20
355
}
356
},
357
setup(props) {
358
const deferrer = useDefer();
359
360
// Chunk items for progressive rendering
361
const itemChunks = hooks.computed(() => {
362
const chunks = [];
363
for (let i = 0; i < props.items.length; i += props.chunkSize) {
364
chunks.push(props.items.slice(i, i + props.chunkSize));
365
}
366
return chunks;
367
});
368
369
// Progressive chunk rendering
370
const visibleChunks = hooks.computed(() => {
371
return itemChunks.value.filter((_, chunkIndex) => {
372
return deferrer.defer(chunkIndex + 1);
373
});
374
});
375
376
const visibleItems = hooks.computed(() => {
377
return visibleChunks.value.flat();
378
});
379
380
// Loading state
381
const isLoading = hooks.computed(() => {
382
return visibleItems.value.length < props.items.length;
383
});
384
385
// Reset on items change
386
hooks.watch(() => props.items, () => {
387
deferrer.reset();
388
});
389
390
return {
391
visibleItems,
392
isLoading,
393
totalItems: hooks.computed(() => props.items.length),
394
loadedItems: hooks.computed(() => visibleItems.value.length)
395
};
396
}
397
};
398
```
399
400
## Integration with Component Setup
401
402
These hooks integrate seamlessly with the component setup system:
403
404
```typescript
405
import { setup, useInstanceSlots, useRelation, useDefer } from "@opentiny/vue-common";
406
407
export default {
408
setup(props, context) {
409
return setup({
410
props,
411
context,
412
renderless: (props, hooks, utils) => {
413
// Use composition hooks within renderless functions
414
const slots = useInstanceSlots(hooks);
415
const relation = useRelation(hooks);
416
const deferrer = useDefer(30);
417
418
return {
419
slots,
420
relation,
421
deferrer
422
};
423
},
424
api: ['slots', 'relation', 'deferrer']
425
});
426
}
427
};
428
```