Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Theme Provider component in React Native

My application needs a color themes providing and I am trying to implement a Theme Providing component using a React Context, but it does not work. I can't figure out how to get the theme prop object from the Theme Provider's Context and how can I call the updateTheme function that is state of Theme Provider? This is my code:

ThemeProvider

import React from "react";
import { LightTheme, DarkTheme } from '../themes'

const Context = React.createContext();

export class ThemeProvider extends React.Component {
  
  state = {
    theme: LightTheme,
    updateTheme: (theme) => {
      this.setState({ theme: theme })
    }
  }

  render() {
    const { theme } = this.state
    return (
      <Context.Provider value={this.state} theme={theme} >
        { this.props.children }
      </Context.Provider>
    )
  }
}

export default ThemeProvider;

App

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { HomeScreen } from './screens';
import { NavBar, ThemeProvider } from './components';

const Stack = createStackNavigator();

const App: () => React$Node = () => {

  return (
    <ThemeProvider>
      <NavigationContainer>
        <StatusBar barStyle="dark-content" />
        <NavBar />
        <Stack.Navigator
          screenOptions={{
            headerShown: false
          }}
        >
          <Stack.Screen name="Home" component={HomeScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    </ThemeProvider>
  );
};

export default App;

Navbar (this component have to get the theme prop from the ThemeProvider to change it's color)

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';

import { Container, Header, Left, Body, Right, Button, Title } from 'native-base';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { Layout } from '../constants';

class NavBar extends React.Component {
  
  static contextType = ThemeProvider;
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Header>
        <Left>
          <Button transparent>
            <Icon name='add' size={Layout.navIconSize} />
          </Button>
        </Left>
        <Body>
          <Title>Header</Title>
        </Body>
        <Right>
          <Button transparent>
            <Icon name='alarm' size={Layout.navIconSize} />
          </Button>
        </Right>
      </Header>
    )
  }
}

export default NavBar;

Themes

export const LightTheme = {
   dark: false,
   colors: {
      primary: 'rgb(255, 45, 85)',
      background: 'rgb(242, 242, 242)',
      card: 'rgb(255, 255, 255)',
      text: 'rgb(28, 28, 30)',
      border: 'rgb(199, 199, 204)',
      notification: 'rgb(255, 69, 58)',
   }
}

export const DarkTheme = {
   dark: true,
   colors: {
      primary: 'rgb(255, 45, 85)',
      background: 'rgb(0, 0, 0)',
      card: 'rgb(255, 255, 255)',
      text: 'rgb(28, 28, 30)',
      border: 'rgb(199, 199, 204)',
      notification: 'rgb(255, 69, 58)',
   },
};
like image 668
Amphyx Avatar asked May 12 '26 16:05

Amphyx


1 Answers

You have done the major part, you just have to do some minor changes to get it to work.

First In order to change the values of a context you will have to export the context. Then access the consumer.

import React from "react";
import { LightTheme, DarkTheme } from '../themes'

export const Context = React.createContext();

export class ThemeProvider extends React.Component {
  
  state = {
    theme: LightTheme,
    updateTheme: (theme) => {
      this.setState({ theme: theme })
    }
  }

  render() {
    const { theme } = this.state
    return (
      <Context.Provider value={this.state} theme={theme} >
        { this.props.children }
      </Context.Provider>
    )
  }
}

export default ThemeProvider;

In the child component which is the NavBar in your case, you will have to import it and use the consumer to do updates Import the context like below (Your actual paths may vary)

import ThemeProvider, { Context } from './ThemeProvider';


class NavBar extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Context.Consumer>
        {({ theme, updateTheme }) => (
          <Header>
            <Left>
              <Button
                title="Update Theme"
                onPress={() => updateTheme(theme.dark ? LightTheme : DarkTheme)}
              />
              <Button transparent>
                <Icon name="add" size={Layout.navIconSize} />
              </Button>
            </Left>
            <Body>
              <Title>Header</Title>
            </Body>
            <Right>
              <Button transparent>
                <Icon name="alarm" size={Layout.navIconSize} />
              </Button>
            </Right>
          </Header>
        )}
      </Context.Consumer>
    );
  }
}

{({ theme, updateTheme }) => ( The above line provides access to your theme value in the context and updateTheme. You can try out the code.

like image 99
Guruparan Giritharan Avatar answered May 14 '26 07:05

Guruparan Giritharan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!