Reputation: 755
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)',
},
};
Upvotes: 3
Views: 14316
Reputation: 16334
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.
Upvotes: 3