I’m facing an issue with updating the content of cards in a swiper using react-native-deck-swiper
. I have a button external to the swiper, and when pressing it I want to update the content of the current card and trigger a re-render to reflect the changes.
I’ve managed to update the state of the item correctly, but the card doesn’t re-render immediately. It only renders again when I start swiping the item.
The documentation suggests a possible fix, stating, "A possible fix for the situation is setting the cardIndex
on the parent component whenever deck re-renders are needed." However, my attempt to implement this hasn’t been successful.
I have noticed that the change is render when the overlay condition are required (even if no overlay is set).
Below is a reproducible example of the problem :
import React, { useRef, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import Swiper from 'react-native-deck-swiper';
const cards = [
{ color: 'red', updated: false },
{ color: 'blue', updated: false },
{ color: 'green', updated: false },
{ color: 'yellow', updated: false },
{ color: 'purple', updated: false },
];
export default function App() {
const [cardIndex, setCardIndex] = useState(0);
const swiperRef = useRef(null);
const updateCard = () => {
cards[cardIndex].updated = !cards[cardIndex].updated;
// Force re-render??
setCardIndex(cardIndex);
};
const onSwiped = () => {
setCardIndex((cardIndex + 1) % cards.length);
};
const renderCard = (card) => (
<View style={[styles.card, { backgroundColor: card.color }]}>
{card.updated && <Text style={styles.updatedText}>UPDATED</Text>}
</View>
);
return (
<View style={styles.container}>
<Swiper
ref={swiperRef}
cards={cards}
renderCard={renderCard}
onSwiped={onSwiped}
onSwipedLeft={onSwiped}
onSwipedRight={onSwiped}
cardIndex={cardIndex}
infinite
/>
<TouchableOpacity style={styles.button} onPress={updateCard}>
<Text style={styles.buttonText}>Update card</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f7f7f7',
alignItems: 'center',
justifyContent: 'center',
},
card: {
width: '80%',
height: '80%',
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'center',
},
updatedText: {
position: 'absolute',
fontSize: 24,
fontWeight: 'bold',
color: 'black',
},
button: {
position: 'absolute',
bottom: 20,
padding: 10,
backgroundColor: 'blue',
borderRadius: 5,
},
buttonText: {
color: 'white',
fontSize: 16,
},
});
I’d appreciate any insights on how to solve this issue and get the card to re-render immediately upon pressing the button. Thank you!
2
Answers
At first, I thought the issue was that you werent storing the cards in a state variable, but after doing so, I found that the cards still wouldnt update, which makes me believe that Swiper component caches card on initialization and ignore all updates to it. This where the key prop comes to play. A component will be reinitialized when its key changes, so if you store the swiperKey in state and the update it, cards will be reinitialized (demo):
Give this a try; it will update the content on the card.