I have a strange issue with material top tabs. I'm trying to fetch data and then display that data inside the tab. However, even if the useQuery data changes, no re-rerender is triggered.
Navigation.tsx
const CulturalHeritageTab =
createMaterialTopTabNavigator<CulturalHeritageTabParamList>();
export const CulturalHeritageTabNavigator = () => {
return (
<CulturalHeritageTab.Navigator>
<CulturalHeritageTab.Group
screenOptions={{
swipeEnabled: false,
tabBarItemStyle: { ...styles.tab },
tabBarLabelStyle: { ...fonts.topButton },
}}>
<CulturalHeritageTab.Screen
name="Tour"
children={CulturalHeritageList}
/>
<CulturalHeritageTab.Screen
name="Exibition"
children={CulturalHeritageList}
/>
</CulturalHeritageTab.Group>
</CulturalHeritageTab.Navigator>
);
};
Page.tsx
export const CulturalHeritageList = () => {
const navigation = useNavigation<CulturalHeritageNavigationProp>();
const { t, i18n } = useTranslation();
const { data, error, loading } = useQuery< //<--- This should rerender
ICulturalHeritageListData,
ICulturalHeritageListVars
>(ALL_CULTURAL_HERITAGE_LIST, {
variables: {
filter: {
where: {
expired: null,
},
},
lang: i18n.language,
},
});
const renderItem = (
{ item, index }: { item: ICulturalHeritageList; index: number },
parallaxProps: AdditionalParallaxProps | undefined,
) => {
const source = { uri: `${API_BUCKET}${item.media.path}` };
const navigateToDetails = () => {
navigation.navigate('CulturalHeritageDetails', { item: item });
};
return (
<View style={styles.item} key={index}>
<ParallaxImage
source={source}
containerStyle={styles.imageContainer}
style={styles.image}
parallaxFactor={0.4}
{...parallaxProps}
/>
<View style={styles.textContainer}>
<Text style={[fonts.cardTitle]}>
{item.culturalHeritageLocale[0].title}
</Text>
<View style={global.divider} />
<Button light width="sm" onPress={navigateToDetails}>
See More
</Button>
<Text style={styles.time}>
<Icon name="time-outline" style={styles.icon} />
{item.duration
? `${
Math.floor(item.duration / 60)
? Math.floor(item.duration / 60) + 'h '
: ''
}${item.duration % 60 ? (item.duration % 60) + 'm' : ''}`
: '- No duration -'}
</Text>
</View>
</View>
);
};
if (error) {
console.log(JSON.stringify(error, null, 2));
}
if (data) {
console.log('CulturalHeritageList: ', data);
}
console.log(loading);
return (
<View style={global.container}>
<ImageBackground source={image} resizeMode="cover" style={styles.image}>
{loading ? (
<ActivityIndicator size="large" />
) : error ? (
<Text>{t('Error')}</Text>
) : data?.culturalHeritages.length ? (
<Carousel
data={data.culturalHeritages}
containerCustomStyle={styles.carousel}
// @ts-ignore
renderItem={renderItem}
sliderWidth={width}
sliderHeight={height * 0.5}
itemWidth={width * 0.5}
itemHeight={height * 0.5}
hasParallaxImages={true}
/>
) : (
<Text>{t('NoDataFound')}</Text>
)}
</ImageBackground>
</View>
);
};
The screen is stuck on ActivityIndicator component as loading and data updates, but no rerender is triggered. It only happens inside Material top tab. How can i rerender this tab when loading or data changes?
Update: This error popped out:
Warning: React has detected a change in the order of Hooks called by SceneView. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks
1. useRef useRef
2. useCallback useCallback
3. useRef useRef
4. useRef useRef
5. useContext useContext
6. useContext useContext
7. useCallback useCallback
8. useEffect useEffect
9. useCallback useCallback
10. useCallback useCallback
11. useEffect useEffect
12. useCallback useCallback
13. useCallback useCallback
14. useCallback useCallback
15. useCallback useCallback
16. useRef useRef
17. useEffect useEffect
18. useEffect useEffect
19. useCallback useCallback
20. useMemo useMemo
21. useContext useContext
22. useState useContext
I had to use component instead of children:
<CulturalHeritageTab.Screen
name="Exibition"
component={CulturalHeritageList}
/>