I am trying to build a workout tracking app. In it, I am displaying the user’s exercises in a horizontal flatlist. I want the page indicator to display the currently viewable page. To do so, I am trying to use the ‘onViewableItemsChanged‘ in the FlatList but for some reason, it won’t update the currently viewable item.
import {
Dimensions,
FlatList,
Image,
StyleSheet,
Text,
View,
} from "react-native";
import React, { useEffect, useState } from "react";
import { PageIndicator } from "react-native-page-indicator";
const styles = {
setCol: {
flex: 1,
},
prevCol: {
flex: 2,
},
kgCol: {
flex: 2,
},
repsCol: {
flex: 1,
},
};
const SetItem = ({ set }) => {
const { width: screenWidth } = Dimensions.get("window");
// console.log(`total: ${totalExercises} current:${current}`)
return (
<View
style={{ width: screenWidth - 32 }}
className="flex-1 justify-start items-center mt-2"
>
<View className="w-full flex justify-start items-start">
<Text className="text-primary font-mregular text-md">{set.name}</Text>
</View>
<View className="flex justify-start items-center mt-2">
<View>
<View className="w-full flex-row justify-start items-center px-2">
<Text
style={styles.setCol}
className="text-gray-500 text-left text-xs"
>
SET
</Text>
<Text
style={styles.prevCol}
className="text-gray-500 text-center text-xs"
>
PREV
</Text>
<Text
style={styles.kgCol}
className="text-gray-500 text-center text-xs"
>
KG
</Text>
<Text
style={styles.repsCol}
className="text-gray-500 text-right text-xs"
>
REPS
</Text>
</View>
</View>
{set.sets.map((item, index) => (
<View className="w-full flex-row justify-start items-center px-2">
<Text style={styles.setCol} className="text-white text-left">
{index + 1}
</Text>
<Text style={styles.prevCol} className="text-white text-center mt-1">
? x ?
</Text>
<Text style={styles.kgCol} className="text-white text-center mt-1">
{item.weight}
</Text>
<Text style={styles.repsCol} className="text-white text-right mt-1">
{item.reps}
</Text>
</View>
))}
</View>
</View>
);
};
const UserInClub = ({ user }) => {
const [totalExercises, setTotalExercises] = useState(0);
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
setTotalExercises(user.exercises.length);
}, []);
// Handle the event when the FlatList viewable items change
const viewableItemsChanged = ({ viewableItems }) => {
if (viewableItems.length > 0) {
console.log(JSON.stringify(viewableItems));
setCurrentIndex(viewableItems[0].index); // Update the index of the current exercise
}
};
return (
<View className="w-full flex justify-start items-center">
<View className="w-full flex-row items-center justify-start space-x-3">
<Image
source={{ uri: user.img_url }}
className="w-8 h-8 rounded-full"
resizeMode="contain"
/>
<Text className="font-mmedium text-md text-white">{user.username}</Text>
</View>
<FlatList
data={user.exercises}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
keyExtractor={(item) => item.$id}
onViewableItemsChanged={viewableItemsChanged} // Attach the viewable items handler
viewabilityConfig={{
itemVisiblePercentThreshold: 70,
}}
renderItem={({ item }) => <SetItem key={item.$id} set={item} />}
/>
<PageIndicator
className="mt-2"
count={totalExercises}
current={currentIndex}
color="#FFFFFF"
/>
</View>
);
};
export default UserInClub;
Here’s what the console.log in the viewableItemsChanged function displays on startup
[{"index":0,"item":{"name":"Lat Pulldown","sets":[{"weight":"60","reps":"11","done":true},{"weight":"65","reps":"7","done":true},{"weight":"60","reps":"6","done":true}]},"isViewable":true}]
It doesn’t get called afterwards no matter how many times the viewable items change.