1

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

Lavínia Beghini
  • 165
  • 1
  • 11

2 Answers2

1

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>
  );
}
Lavínia Beghini
  • 165
  • 1
  • 11
0

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>
  );
}
Sai kiran
  • 237
  • 3
  • 15
  • I really thought it would work, but unfortunately when I click the toggle button to change the app theme, only the calendar doesnt. I will provide a few images of the behavior, it might help in something – Lavínia Beghini Feb 15 '23 at 12:34