Search code examples
react-nativethemes

React Native - What's the best way to provide a global theme?


I've started using RN recently and have been doing some research on the implementation of themes and/or a dark-light mode. Here's roughly how I understand the two main options so far:

  • Context: Easy setup and can be accessed via hook inside the component that needs it. I count things like the React Navigation themes since that works, in essence, the same way(?)
  • Styled Components: Essentially just replacing the components with custom ones that access the current theme and that can then be set up to change their props on toggle if needed.

What I don't like about context, is that (the way I understand it) it wouldn't let me access the theme when using a StyleSheet, since that's outside the component. With the styled components on the other hands I'm not sure if I can cover all options inside my custom components, wouldn't I still need some sort of hook in each component anyway?

I was also thinking about just saving the current theme into my Store (in my case Zustand), together with an action that lets me toggle to a dark-mode. But so far, I haven't really seen anyone else do that, is there a downside to doing it that way?


Solution

  • It's not hard to pass context to your stylesheet, it just requires a bit of extra boilerplate. Something like the below:

    import ThemeContext from '<path>';
    
    export default () => {
      const theme = useContext(ThemeContext);
      const stylesWithTheme = styles(theme);
    
      return <Text style={stylesWithTheme.text}>Hi</Text>;
    }
    
    const styles = (theme) => StyleSheet.create({
      text: {
        color: themeStyles.color[theme];
      },
    });
    
    const themeStyles = {
      color: {
        dark: '#FFF',
        light: '#000',
      },
    };
    

    I don't think using styled components would be a big departure from the above scheme.

    If you did store your theme in state, and define your styles within the body of the component, that could be a savings in boilerplate. It's up to you whether having your styles in the component body is acceptable.

    Side note, if you're already using a state manager, I would recommend not mixing it with the Context API without knowing more. It's simpler to have one solution there.