admin管理员组文章数量:1333442
I'm building a React Native app with a stack of cards that users can swipe through. The card at the top of the stack is animated off-screen when swiped, and the next card in the stack becomes the new top card.
Everything works as expected, except for a flickering issue: after a swipe animation completes, the card that was just swiped briefly reappears at the top before disappearing. Here's what I'm doing:
Key Features:
Stack Structure: The card stack is managed using an array of post IDs (cardOrder), where the top card is always at cardOrder[0].
Animation: The swipe is implemented with Animated.ValueXY for position and PanResponder for drag gestures.
Reorder: When a card is swiped off the screen, the array is shifted so that the card's id goes from the first element to the last
Key Prop: I use a combination of postID and index for the key prop in the map function.
My Code:
Here’s the relevant part of my code for rendering the stack:
{cardOrder.map((postID, index) => {
const isTopCard = index === 0;
const post = posts.find((p) => p.id === postID);
return (
<Animated.View
{...(isTopCard ? panResponder.panHandlers : {})}
key={`${postID}-${index}`}
style={[
styles.card,
{
opacity: index < 5 ? 1 : 0, // Hide cards beyond the top 5
top: height * 0.2,
transform: [
{ translateX: isTopCard ? position.x : 8 * index },
{ translateY: isTopCard ? position.y : 0 },
],
},
]}
>
<Post post={post} />
</Animated.View>
);
})}
Here is the relevant code from the panResponder:
onPanResponderRelease: (_, gesture) => {
// when the user releases the card, check if it should be swiped off the screen
if (gesture.dx > 120 || gesture.dx < -120) {
const offScreenX = gesture.dx > 0 ? width + 100 : -width - 100;
Animated.timing(position, {
toValue: { x: offScreenX, y: gesture.dy },
duration: 300,
useNativeDriver: false,
}).start(() => {
handleSwipe(); // move the top card to the back of the stack and next card to the top
});
Here is the relevant part of the handleSwipe function:
// update the card order
setCardOrder((prevOrder) => {
const newOrder = [...prevOrder];
newOrder.push(newOrder.shift()); // Move the top card to the end
return newOrder;
});
// reset the position of the top card
position.setValue({ x: 0, y: 0 });
What I’ve Tried:
- Using unique postID as the key prop alone.
Result: When I swipe a card, I move the top card's postID from index 0 to the end of the cardOrder array. React sees that the same key (postID) is now at a different position and optimizes by reusing the component, which causes visual glitches such as flickering and a second stack appearing.
- Using index as the key prop instead of postID.
Result: Flickering stops, but the stack breaks when the card order updates dynamically.
My Hypothesis:
I suspect the issue is related to how React Native re-renders components when the key prop changes, possibly causing the top card to momentarily reappear. The whole problem is that the card shift, apparently, happens after the animation, resulting in the swiped card momentarily appearing as the top card before disappearing. That's what makes it visually not appealing.
Question:
Is there a way to make the card that is swiped not appear again as the top card after the animation?
Any guidance or insights would be appreciated! Let me know if more code or context is needed.
本文标签:
版权声明:本文标题:reactjs - Why does my top card briefly reappear after a swipe in my React Native animated card stack? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742354793a2459192.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论