Skip to content

Commit 4a250c7

Browse files
authored
perf(useSlots): pre-compute array matcher type, update snapshots
1 parent 91ac722 commit 4a250c7

File tree

1 file changed

+16
-18
lines changed

1 file changed

+16
-18
lines changed

packages/react/src/hooks/useSlots.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,25 @@ export function useSlots<Config extends SlotConfig>(
3838
children: React.ReactNode,
3939
config: Config,
4040
): [Partial<SlotElements<Config>>, React.ReactNode[]] {
41-
// Object mapping slot names to their elements
42-
const slots: Partial<SlotElements<Config>> = {} as Partial<SlotElements<Config>>
43-
4441
// Array of elements that are not slots
4542
const rest: React.ReactNode[] = []
4643

4744
const keys = Object.keys(config) as Array<keyof Config>
4845
const values = Object.values(config)
4946
const totalSlots = keys.length
50-
let slotsFound = 0
47+
48+
// Object mapping slot names to their elements, initialized with undefined for each key
49+
const slots: Partial<SlotElements<Config>> = {} as Partial<SlotElements<Config>>
50+
for (let i = 0; i < totalSlots; i++) {
51+
slots[keys[i]] = undefined
52+
}
53+
54+
// Pre-compute which slots use the [Component, testFn] matcher pattern
55+
// to avoid Array.isArray() checks in the hot inner loop
56+
const isArrayMatcher: boolean[] = new Array(totalSlots)
57+
for (let i = 0; i < totalSlots; i++) {
58+
isArrayMatcher[i] = Array.isArray(values[i])
59+
}
5160

5261
// eslint-disable-next-line github/array-foreach
5362
React.Children.forEach(children, child => {
@@ -56,26 +65,16 @@ export function useSlots<Config extends SlotConfig>(
5665
return
5766
}
5867

59-
// Short-circuit: if all slots are filled, remaining children go to rest
60-
if (slotsFound === totalSlots) {
61-
rest.push(child)
62-
return
63-
}
64-
6568
let matchedIndex = -1
6669
for (let i = 0; i < totalSlots; i++) {
67-
// Skip already-filled slots
68-
if (slots[keys[i]] !== undefined) continue
69-
70-
const value = values[i]
71-
if (Array.isArray(value)) {
72-
const [component, testFn] = value
70+
if (isArrayMatcher[i]) {
71+
const [component, testFn] = values[i] as ComponentAndPropsMatcher
7372
if ((child.type === component || isSlot(child, component as SlotMarker)) && testFn(child.props)) {
7473
matchedIndex = i
7574
break
7675
}
7776
} else {
78-
if (child.type === value || isSlot(child, value as SlotMarker)) {
77+
if (child.type === values[i] || isSlot(child, values[i] as SlotMarker)) {
7978
matchedIndex = i
8079
break
8180
}
@@ -98,7 +97,6 @@ export function useSlots<Config extends SlotConfig>(
9897

9998
// If the child is a slot, add it to the `slots` object
10099
slots[slotKey] = child as SlotValue<Config, keyof Config>
101-
slotsFound++
102100
})
103101

104102
return [slots, rest]

0 commit comments

Comments
 (0)