Back to Blog

How to Create a Smooth, Infinite Tinder-Style Swipe Deck in React Native

Royan Gagas
November 3, 2025
Share
product
mobile application
development
How to Create a Smooth, Infinite Tinder-Style Swipe Deck in React Native

The Tinder-style swipe card UI is an iconic and intuitive pattern for mobile apps. Whether you're building a habit tracker, a to-do list, or social app, giving users the ability to "swipe" through items is incredibly engaging.

But while many libraries can help you create a basic swipe deck, two major problems quickly appear:

1.How do you make the deck infinite, so the cards loop back around?
2.How do you do it without lag or janky animations?

In this guide, based on my video Make Swipe Card like Tinder/Bumble Deck in React Native, I'll show you exact method I used to solve these problems using the rn-swiper-list library and a clever setTimeout trick.

The Stack: What We're Using

React Native
rn-swiper-list: The core library for the swipe deck.
React Query: for fetching our data (e..g., our list of habits).
Zustand: For simple state management.

The "Infinite Loop" Challenge

The first challenge is creating an infinite deck. When a user swipes the last card, we want the first card to reappear.

The logic I implemented is simple:

1.Our data is an array of habits, stored in a state.
2.When a card is swipped (e.g., onSwipedRight or onSwipedLeft), it's not removed.
3.Instead, we call a function (let's call it moveToEnd) that simply takes the first item in the array and moves it to the end of the array.
4.By passing a key prop to the swiper component (based on the data), this state update forces React to rerender the deck, effectively "looping" the cards.

The "Lag" Problem: Why Your Animation is Janky

Here's where 90% of developers get stuck.

You set up the logic above, and it works... but it looks terible. When you swipe, there's a noticeable lag or jank [09:00].

Why does this happen? The swipe animation itself has a duration. The rn-swiper-list library defaults to an animation of about 500ms [09:12]. Your code, however, is updating the state (moving the card in the array) immediately.

You are forcing a state update and rerender while the card's exit animation is still playing. The two are fighting each other, resulting in a laggy, unprofessional-looking animation.

The Solution: The 500ms setTimeout Trick

The fix is surprisingly simple, but critical for a smooth user experience.

Do not update the state immediately. Wait for the animation to finish first.

Since we know the animation duration is 500ms, we wrap our state update function (moveToEnd) inside a setTimeout call with a 500ms delay.

By doing this [09:25], we let the card swipe off-screen completely. The animation finishes, and then the state updates silently in the background. The next card slides in, and the user experiences a perfectly smooth, seamless, and infinite loop.

Bonus Tip: Triggering Swipes from Inside the Card

What if you don't want external like or nope buttons? In my app, I wanted buttons inside the card itself to trigger the swipe.

You can achieve this by using a ref:

1.Create a ref in your component: const swiperRef = useRef(null);
2.Pass the ref to the swiper component: <Swiper ref={swiperRef} ../>
3.Pass the ref down to your child card component: <HabitCard card={card} swiperRef={swiperRef} />
4.Inside your HabitCard component, you can now add a Pressable button that calls the swiper's built-in methods:

This gives you full control over the swipe deck, allowing you to build complex, custom UIs just like Tinder or Bumble.

youtube_embed_preview