Skip to content

Commit c77dbc3

Browse files
authored
refactor(react-router): Link component composeHandler performance (#5168)
I noticed a slight performance dip during some navigations and the bottom-up call list of the flame graph seemed to point to the `composeHandler`. This seems (surprising and) pretty minor, but I'm measuring a consistent 3ms self-time when the resulting handler is actually being called. This PR proposes ditching array methods and using a `for-of` loop. This is good-enough™ and preserves the generality and DX of this function for a 25% perf improvement. ```sh ✓ @tanstack/react-router tests/foo.bench.tsx > composeHandlers 10064ms name hz min max mean p75 p99 p995 p999 rme samples · array methods 37,152,711.10 0.0000 0.1624 0.0000 0.0000 0.0000 0.0000 0.0002 ±0.14% 18576357 · for-of 47,029,751.81 0.0000 0.0236 0.0000 0.0000 0.0000 0.0000 0.0001 ±0.07% 23514876 fastest BENCH Summary @tanstack/react-router for-of - tests/foo.bench.tsx > composeHandlers 1.27x faster than array methods ``` A slightly more performant (~30%) version would be to handle *exactly* 2 handlers instead of an arbitrary number (since `composeHandlers` is only used w/ 2 callbacks) but this does affect the generality and DX of this function. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Refactor** - Updated link event handling to short-circuit when an action is prevented, maintaining existing behavior. - Streamlined internal logic for handling user interactions with links for improved efficiency. - **Performance** - Minor efficiency improvements in link interaction handling without altering the public API or user-facing behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent fb4c6a1 commit c77dbc3

File tree

1 file changed

+4
-3
lines changed

1 file changed

+4
-3
lines changed

packages/react-router/src/link.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,11 @@ const intersectionObserverOptions: IntersectionObserverInit = {
374374
const composeHandlers =
375375
(handlers: Array<undefined | React.EventHandler<any>>) =>
376376
(e: React.SyntheticEvent) => {
377-
handlers.filter(Boolean).forEach((handler) => {
377+
for (const handler of handlers) {
378+
if (!handler) continue
378379
if (e.defaultPrevented) return
379-
handler!(e)
380-
})
380+
handler(e)
381+
}
381382
}
382383

383384
type UseLinkReactProps<TComp> = TComp extends keyof React.JSX.IntrinsicElements

0 commit comments

Comments
 (0)