I've spent the last 3 hours thinking about an easy way to switch app themes at runtime and I found a really easy solution! :)

I want to share it with you because there're not many examples in the internet as far as I can conclude from my time spent researching.

So, fast-forward, we will use the React Context API and React Native Paper library for this example.

1. First, we have to create a new class which will provide the context:

import React, { Component } from "react";

const Context = React.createContext();

export class AppContextProvider extends Component {
    render() {
        return (
            ...
        )
    }
}

export const AppConsumer = Context.Consumer;
export const AppContext = Context;

2. Lets create some themes in a separate file called Themes.js

import { DefaultTheme } from "react-native-paper";

export const BlueGray = {
    ...DefaultTheme,
    colors: {
        ...DefaultTheme.colors,
        primary: '#607d8b'
    }
}

export const LightGreen = {
    ...DefaultTheme,
    colors: {
        ...DefaultTheme.colors,
        primary: '#8bc34a'
    }
}

3. Now we have to initialize the default state of the AppContextProvider class and add a method for updating the theme object

import React, { Component } from "react";
import { BlueGray, LightGreen } from './Themes'

const Context = React.createContext();

export class AppContextProvider extends Component {
    state = {
        theme: LightGreen,
        updateTheme: (theme) => {
            this.setState({ theme: theme })
        }
    }
    
    render() {
        return (
            ...
        )
    }
}

export const AppConsumer = Context.Consumer;
export const AppContext = Context;

4. The last thing we have to implement in the AppContextProvider class is the render() method. There we will provide our context that will be accessable by the child components in order to switch our themes

import React, { Component } from "react";
import { BlueGray, LightGreen } from './Themes'

const Context = React.createContext();

export class AppContextProvider extends Component {
    state = {
        theme: LightGreen,
        updateTheme: (theme) => {
            this.setState({ theme: theme })
        }
    }
    
    render() {
        const { theme } = this.state
        return (
            <Context.Provider value={ this.state }>
                <PaperProvider theme={ theme }> // Setting our theme
                    { this.props.children }
                </PaperProvider>
            </Context.Provider>
        )
    }
}

export const AppConsumer = Context.Consumer;
export const AppContext = Context;

4. Lets go back in the main App.js class and add our AppContextProvider

import React, { Component } from "react";
import { AppContextProvider } from './AppContextProvider'

class App extends Component {
    render() {
        return (
            <AppContextProvider>
                ... // Children Components
            </AppContextProvider>
        )
    }
}

export default App

5. Lets say you have a SettingsScreen component class and want to switch the current theme from it by clicking on buttons

import React, { Component } from "react";
import { View } from 'react-native'
import { AppConsumer } from './AppContextProvider'
import { BlueGray, LightGreen } from './Themes'

class SettingsScreen extends Component {
    render() {
        return (
            <AppConsumer>
                { appConsumer => (
                     <View>
                         <Button onPress={ () => appConsumer.updateTheme(BlueGray) }>Blue Gray Theme</Button>
                         <Button onPress={ () => appConsumer.updateTheme(LightGreen) }>Light Green Theme</Button>
                     </View>
                )}
            </AppConsumer>
        )
    }
}

export default App

So, now if you open the Settings Screen and click on any of those two buttons, the theme will be changed dynamically!

Woa! And it's so simple! 🥳