Managing Themes in React Native Using Context API
Amit Kumar
Posted on September 21, 2024
In modern React Native apps, managing global states like themes can be cumbersome if not done efficiently. One of the most elegant solutions for managing application-wide states is the Context API. In this article, we’ll explore how to implement dark and light themes in a React Native app using the Context API and React Native’s Appearance module.
Why Use the Context API?
The Context API provides a way to pass data through the component tree without having to pass props down manually at every level. For global themes, this is an ideal choice as it helps manage the UI’s look and feel across the entire app seamlessly.
Step-by-Step Guide
1. Setting Up the ThemeContext
We’ll first create a ThemeContext
to store and manage our theme data. This will allow us to access and modify the theme throughout the app.
Create a ThemeContext
in your src/contexts/ThemeContext/index.js:
import { Appearance } from 'react-native';
import React, {
createContext,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
export const ThemeContext = createContext({});
export const ThemeConsumer = ({ children }) => (
<ThemeContext.Consumer>
{(context) => {
if (context === undefined) {
throw new Error('ThemeConsumer must be used within a ThemeProvider');
}
return children(context);
}}
</ThemeContext.Consumer>
);
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState(Appearance.getColorScheme());
const setAppMode = () => {
setTheme(Appearance.getColorScheme());
};
const themeChangeListener = useCallback(() => {
setTheme(Appearance.getColorScheme());
}, []);
useEffect(() => {
const themeListener = Appearance.addChangeListener(themeChangeListener);
return () => themeListener.remove();
}, [themeChangeListener]);
const MemoizedValue = useMemo(() => ({
theme,
setAppMode,
}), [theme]);
return (
<ThemeContext.Provider value={MemoizedValue}>
{children}
</ThemeContext.Provider>
);
};
2. Wrapping the App with ThemeProvider
To ensure the theme is accessible throughout the app, wrap the root of your app with ThemeProvider in App.js:
import React from 'react';
import { Provider } from 'react-redux'; // Assuming you're using Redux
import { ThemeProvider } from './src/contexts/ThemeContext';
const App = () => {
return (
<Provider store={store}>
<ThemeProvider>
{/* Other components */}
</ThemeProvider>
</Provider>
);
};
export default App;
Now, the entire app has access to the theme and can react to changes in theme mode.
3. Using the ThemeContext
in Components
Let’s modify a component to dynamically change based on the theme.
import React, { useContext } from 'react';
import { StatusBar } from 'react-native';
import { ThemeContext } from '../src/contexts/ThemeContext';
const MyComponent = () => {
const { theme = 'light' } = useContext(ThemeContext);
return (
<StatusBar barStyle={theme === 'dark' ? 'light-content' : 'dark-content'} />
);
};
export default MyComponent;
In this example, the StatusBar
changes its barStyle
based on whether the app is in dark mode or light mode.
4. Applying Theme to the Entire UI
You can apply the theme to other components to change their styles dynamically:
import React, { useContext } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { ThemeContext } from '../src/contexts/ThemeContext';
const ThemedView = () => {
const { theme } = useContext(ThemeContext);
return (
<View style={theme === 'dark' ? styles.darkContainer : styles.lightContainer}>
<Text style={theme === 'dark' ? styles.darkText : styles.lightText}>
Hello, {theme === 'dark' ? 'Dark' : 'Light'} Theme!
</Text>
</View>
);
};
const styles = StyleSheet.create({
darkContainer: {
backgroundColor: '#333',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
lightContainer: {
backgroundColor: '#fff',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
darkText: {
color: '#fff',
},
lightText: {
color: '#000',
},
});
export default ThemedView;
Handling Theme Changes
When the device's appearance
changes (e.g., when the user switches to dark mode), the Appearance API will trigger the themeChangeListener
. This will automatically update the theme
in your app.
Final Thoughts
The Context API, combined with React Native’s Appearance
module, offers a simple and powerful way to handle themes in your app. This approach ensures that theme-related logic is centralized and easy to maintain. With this setup, you can quickly scale your theme system and apply it throughout your app.
Posted on September 21, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.