skip to Main Content

I am trying to use any calendar component from the react-native-calendars library, however I am not being able to match the calendar colors with my given theme.

For exemple, I have the following code:

export default function Statistics({ navigation }) {
  const theme = useTheme();


  return (
      <CalendarList
        firstDay={1}
        pastScrollRange={1}
        futureScrollRange={1}
        scrollEnabled
        showScrollIndicator={false}
        theme={{
          backgroundColor: theme.colors.background,
          calendarBackground: theme.colors.background, 
          textSectionTitleColor: theme.colors.onBackground,
          selectedDayBackgroundColor: 'transparent',
          selectedDayTextColor: theme.colors.onBackground,
          todayTextColor: theme.colors.onBackground,
          todayBackgroundColor: theme.colors.primary,
          dayTextColor: 'gray', //Disabled days
          dotColor: theme.colors.primary,
          selectedDotColor: theme.colors.onBackground,
          monthTextColor: theme.colors.onBackground,
        }}
      />
    </SafeAreaView>
  );
}

Where theme comes from react-native-paper theming provider, and I am using it also in the app context:

function App() {
  const [isThemeDark, setIsThemeDark] = React.useState(false);

  const theme = isThemeDark ? CombinedDarkTheme : CombinedDefaultTheme;

  const toggleTheme = React.useCallback(() => {
    return setIsThemeDark(!isThemeDark);
  }, [isThemeDark]);

  const preferences = React.useMemo(
    () => ({
      toggleTheme,
      isThemeDark,
    }),
    [toggleTheme, isThemeDark]
  );

  return (
    <PaperProvider theme={theme}>
      <PreferencesContext.Provider value={preferences}>
        <>
          <RootNavigation theme={theme} />
        </>
      </PreferencesContext.Provider>
    </PaperProvider>
  );
}

That toggleTheme over there is being use in a toggleButton component I have somewhere else in the code. When I click it, everything else changes background as expected, but the calendar no.

However, if I go back and forth in the screens, it changes color. I am guessing it is because the calendar library is not being able to tell that it needs to re-render the component once the color changes.

I wonder if there is a way to force this component re-rendering? I am not sure what to do here.

Light Theme App
Drawer with theme toggle button
Drawer with theme toggle button pressed
Dark theme app

2

Answers


  1. Chosen as BEST ANSWER

    I ended up figuring out the answer. Since I noticed the problem was with re-rendering, I wrapped the CalendarList component inside a View component and conditionally apply a key prop to it based on the current theme. This forced the CalendarList component to re-render whenever the theme changes.

    export default function Statistics({ navigation }) {
      const { isThemeDark } = React.useContext(PreferencesContext);
      const theme = isThemeDark ? CombinedDarkTheme : CombinedDefaultTheme;
      const [themeId, setThemeId] = React.useState(isThemeDark ? 'dark' : 'light');
    
      React.useEffect(() => {
        setThemeId(isThemeDark ? 'dark' : 'light');
      }, [isThemeDark]);
    
      const calendarKey = isThemeDark ? 'dark' : 'light';
    
      return (
        <SafeAreaView style={styles.container}>
          <View key={calendarKey} style={{ backgroundColor: theme.colors.background }}>
            <CalendarList
              firstDay={1}
              pastScrollRange={1}
              futureScrollRange={1}
              scrollEnabled
              showScrollIndicator={false}
              theme={{
                backgroundColor: theme.colors.background,
                calendarBackground: theme.colors.background,
                textSectionTitleColor: theme.colors.onBackground,
                selectedDayBackgroundColor: 'transparent',
                selectedDayTextColor: theme.colors.onBackground,
                todayTextColor: theme.colors.onBackground,
                todayBackgroundColor: theme.colors.primary,
                dayTextColor: 'gray',
                dotColor: theme.colors.primary,
                selectedDotColor: theme.colors.onBackground,
                monthTextColor: theme.colors.onBackground,
              }}
            />
          </View>
        </SafeAreaView>
      );
    }
    

  2. According to the react-native-calendars documentation, CalendarList accepts Flatlist Props . Which means you can make use of extraData Prop from flatlist to re-render the calendar on theme changes.

    It can be something as follows

    export default function Statistics({ navigation }) {
      const theme = useTheme();
    
    
      return (
          <CalendarList
            firstDay={1}
            pastScrollRange={1}
            futureScrollRange={1}
            scrollEnabled
            showScrollIndicator={false}
            theme={{
              backgroundColor: theme.colors.background,
              calendarBackground: theme.colors.background, 
              textSectionTitleColor: theme.colors.onBackground,
              selectedDayBackgroundColor: 'transparent',
              selectedDayTextColor: theme.colors.onBackground,
              todayTextColor: theme.colors.onBackground,
              todayBackgroundColor: theme.colors.primary,
              dayTextColor: 'gray', //Disabled days
              dotColor: theme.colors.primary,
              selectedDotColor: theme.colors.onBackground,
              monthTextColor: theme.colors.onBackground,
            }}
            extraData={theme}
          />
        </SafeAreaView>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search