Search code examples
react-nativegraphqlapolloapollo-clientreact-native-navigation

React native navigation - Material top tabs not re-rendering when state changes


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


Solution

  • I had to use component instead of children:

            <CulturalHeritageTab.Screen
              name="Exibition"
              component={CulturalHeritageList}
            />