Skip to content

perf: optimizations - #35

Open
petrkonecny2 wants to merge 3 commits into
mainfrom
perf/optimizations
Open

petrkonecny2 wants to merge 3 commits into
mainfrom
perf/optimizations

Conversation

@petrkonecny2

@petrkonecny2 petrkonecny2 commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Performance and smoothness fixes found while testing the carousel in the Ascension app on a device. One commit each.

perf: interpolate over the points near the slide only. interpolateInsideCarousel, behind useInterpolateInsideCarousel, built and searched one point per slide on every frame, for every slide using it. A long carousel got slower with every slide it had. Only the points around the slide, and around its clone with infinite scroll, change the result. Every other point sits on a flat stretch between two of those, so the helper now builds at most six points. The output is identical: a new test checks it against the previous all-slides version across 2 to 12 slides, three value sets including an offset, and both infinite modes.

fix: stop the row jumping when a drag starts or the carousel re-renders. Three problems in AnimatedPagedView:

  • A jump at the start of every drag. The pan activated after 30pt of movement, but onUpdate subtracted translationX, which is measured from where the finger first touched down. The row jumped by about 30pt on activation. The starting point now includes the movement made before activation.
  • Vertical scrolls could drag the carousel. minDistance counts movement in any direction, so scrolling a parent past the carousel could grab it, shift it sideways and snap it when the parent took the gesture back. The pan now uses activeOffsetX([-10, 10]) and failOffsetY([-10, 10]), so it only starts on horizontal movement and gives way to vertical scrolling.
  • The gesture was rebuilt during drags. Gesture.Pan() was created on every render, and the carousel re-renders while it's dragged. It's now memoized, and the adapter's onScrollBeginDrag is stable so the memo holds.

perf: remove renderWindow. Added in #32, it unmounted slides far from the current one. On a device it made swiping worse:

  • Slides mounted as they entered the window, during the snap animation, and building their views mid-animation made the swipe stutter.
  • The page tracking behind it re-rendered the carousel on every page change, even with no window set.

Every slide stays mounted again. Removing it also removes isInRenderWindow and its tests, and the README row. This is a breaking change for anyone who passes renderWindow, but it only shipped in 0.1.15, today.

Testing: type:check, lint, test (38 passing) and Prettier. In the Ascension app, all three changes were patched in together. On a phone, swiping was choppy with renderWindow and smooth without it. On the iOS simulator, swipes still page and land centred. The drag-start jump fix follows from the code, but nobody has compared it side by side on a device.

Related Tickets/Issues

Follow-up to #32 and #34.

🤖 Generated with Claude Code

📦 Published PR as canary version: 0.1.18--canary.35.f944505.0

✨ Test out this PR locally via:

npm install @strv/react-native-hero-carousel@0.1.18--canary.35.f944505.0
# or 
yarn add @strv/react-native-hero-carousel@0.1.18--canary.35.f944505.0

Petr Konecny and others added 3 commits October 10, 2026 23:00
interpolateInsideCarousel built and searched one point per slide on every frame, for every slide using it, so a long carousel got slower the more slides it had. Only the points around the slide and around its clone change the result, so it builds those alone. The result is identical, which a test checks against the old all-slides version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pan activated only after 30pt of movement in any direction, but onUpdate subtracted the translation from where the finger first touched, so the row jumped by that distance when a drag started. The starting point now counts the movement made before activation.

The pan now activates on horizontal movement only and fails on vertical movement, so scrolling a parent past the carousel no longer drags and snaps it. The gesture is memoized, and the adapter's drag callback is stable, so a re-render during a drag no longer hands the detector a new gesture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mounting slides as they entered the window happened during the snap animation, and the page tracking behind it re-rendered the carousel on every page change, even without a window. Building the new slide's views mid-animation made swiping visibly stutter, which cost more than keeping every slide mounted saved. Every slide stays mounted again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
npm — f9445057 Deployed Oct 10, 2026 by petrkonecny2 via Publish #60
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant