wix / react-native-calendars

React Native Calendar Components 🗓️ 📆
MIT License
9.58k stars 2.96k forks source link

Changing theme dynamically #982

Open jondesam opened 5 years ago

jondesam commented 5 years ago

is there any way to change theme dynamically depends on state or props?

I found #322 but still wonder any other possible ways to change theme dynamically

Simek commented 5 years ago

Maybe anyone has an idea how to work around that issue? I have failed miserably few times with different approaches (not involving source editing).

Unfortunately react-native-calendars is now the only one package which stops our app new release introducing Dark Mode support on iOS.

Also could an owner or contributor tell us how much effort and/or how difficult it will be to introduce dynamic styles? I'm open to help with development during next weekend if you're interested.

reubn commented 4 years ago

Having the same problem. It's a slight hack but I solved the problem by setting the key prop based on the theme i.e

const [{key, theme}, setTheme] = useState({key: 'dark', theme: {...}})
...
<Calendar key={key} theme={theme} />

When the theme changes, so does the key, so the Calendar rerenders only when the theme changes.

amol251 commented 4 years ago

Having the same problem. It's a slight hack but I solved the problem by setting the key prop based on the theme i.e

const [{key, theme}, setTheme] = useState({key: 'dark', theme: {...}})
...
<Calendar key={key} theme={theme} />

When the theme changes, so does the key, so the Calendar rerenders only when the theme changes.

Yes, but it will re-render the calendar. As the styles are constructed in the constructor you can't change the theme.

I had achieved this by making changes in style creation

https://drive.google.com/open?id=1mZOVjOjuQdiesgnzvkxQXPd5LUpIFkkW

reubn commented 4 years ago

What exactly did you change?

amol251 commented 4 years ago

you can use this code

https://drive.google.com/open?id=1FRwJGiv-9_yNIutnqJ8ZLMb3ZzKIih2Y

run the example.

eqlion commented 4 years ago

@amol251, your link does not work :(

narender2031 commented 4 years ago

@amol251 Can your share your changes

amol251 commented 4 years ago

Link: https://drive.google.com/open?id=1FRwJGiv-9_yNIutnqJ8ZLMb3ZzKIih2Y

This link is working, check this code

chenei commented 4 years ago

Do you have any idea how we can support it? @ethanshar @emilisb

ethanshar commented 4 years ago

It's a little problematic. The way the Calendar component was designed is so the theme prop is more of an initialTheme prop. It is being used only when the component constructed. This making it an un-controlled component (theme wise)

One solution is to use key (as already suggested here). But since Calendar is a huge component it can heavily affect on performance.

Using getDerivedStateFromProps is impossible, because we're keeping the generated style as a class member (on this) and getDerivedStateFromProps is a static method.

The only right solution is to turn this prop (theme) to a controlled prop. But unfortunately, this requires a lot of work and possibly introduce breaking changes.

glushkina1 commented 2 years ago

thanks a lot, @amol251!

Btw, I don't think that useState is a good way to solve this problem if someone is needed to pass more than two params, here's my solution:


const keyRender = (selectedDate: Date, theme: string) => {
        const date = dateFormatter(selectedDate) // '2012-02-02'
        return `${date}-${theme}` 
    }

<Calendar
      key={keyRender(selectedDate,theme)}
/>
manueldeprada commented 8 months ago

I will leave here the full copy-paste solution for dark mode, using the approach from the first post:

const themes = {
  light: {
    calendarBackground: 'white',
    dayTextColor: 'black',
    monthTextColor: 'black',
    textDisabledColor: 'grey',
  },
  dark: {
    calendarBackground: 'black',
    dayTextColor: 'white',
    monthTextColor: 'white',
    textDisabledColor: 'grey',
  }
};
    const {colorScheme} = useColorScheme();
    const [{key, theme}, setTheme] = useState({key: colorScheme, theme: themes[colorScheme]});
    useEffect(() => {
       setTheme({key: colorScheme, theme: themes[colorScheme]});
     }, [colorScheme]);

return (
        <Calendar
          key={key}
          theme={theme}
...
dataforce-kelvin commented 3 months ago

I've managed to get dark mode working on the Agenda control with the following update:

https://github.com/dataforce-kelvin/react-native-calendars/commit/eb2109a49a7c91b569b9071a235aedfa5c5c5850

Functional components were easier as I could just replace:

const style = useRef(styleConstructor(theme));

with:

const style = useMemo(() => styleConstructor(theme), [ theme ]);

and replace all of the style.current references with just style.

For the class components, I either detected the change in shouldComponentUpdate or forceUpdate'd within componentDidUpdate.

I expect the commit above to be far from complete, but it went just far enough for my needs.