Skip to content

Commit 91c8339

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

File tree

2 files changed

+11
-20
lines changed

2 files changed

+11
-20
lines changed

packages/react/src/hooks/__tests__/useSlots.test.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,7 @@ test('handles empty children', () => {
130130
expect(calls).toMatchInlineSnapshot(`
131131
[
132132
[
133-
{
134-
"a": undefined,
135-
"b": undefined,
136-
},
133+
{},
137134
[],
138135
],
139136
]
@@ -165,7 +162,6 @@ test('ignores nested slots', () => {
165162
[
166163
{
167164
"a": <TestComponentA />,
168-
"b": undefined,
169165
},
170166
[
171167
<div>

packages/react/src/hooks/useSlots.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,13 @@ export function useSlots<Config extends SlotConfig>(
4747
const keys = Object.keys(config) as Array<keyof Config>
4848
const values = Object.values(config)
4949
const totalSlots = keys.length
50-
let slotsFound = 0
50+
51+
// Pre-compute which slots use the [Component, testFn] matcher pattern
52+
// to avoid Array.isArray() checks in the hot inner loop
53+
const isArrayMatcher: boolean[] = new Array(totalSlots)
54+
for (let i = 0; i < totalSlots; i++) {
55+
isArrayMatcher[i] = Array.isArray(values[i])
56+
}
5157

5258
// eslint-disable-next-line github/array-foreach
5359
React.Children.forEach(children, child => {
@@ -56,26 +62,16 @@ export function useSlots<Config extends SlotConfig>(
5662
return
5763
}
5864

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-
6565
let matchedIndex = -1
6666
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
67+
if (isArrayMatcher[i]) {
68+
const [component, testFn] = values[i] as ComponentAndPropsMatcher
7369
if ((child.type === component || isSlot(child, component as SlotMarker)) && testFn(child.props)) {
7470
matchedIndex = i
7571
break
7672
}
7773
} else {
78-
if (child.type === value || isSlot(child, value as SlotMarker)) {
74+
if (child.type === values[i] || isSlot(child, values[i] as SlotMarker)) {
7975
matchedIndex = i
8076
break
8177
}
@@ -98,7 +94,6 @@ export function useSlots<Config extends SlotConfig>(
9894

9995
// If the child is a slot, add it to the `slots` object
10096
slots[slotKey] = child as SlotValue<Config, keyof Config>
101-
slotsFound++
10297
})
10398

10499
return [slots, rest]

0 commit comments

Comments
 (0)