Performance
Uses useMemo
to prevent unnecessary style recalculations, improving component performance.
The useThemedStyles
hook provides a performant way to create theme-aware styles in React Native applications. It automatically memoizes style objects and recreates them only when the theme changes.
import { useThemedStyles } from 'your-theme-package';
function MyComponent() {const styles = useThemedStyles((theme) => ({ container: { backgroundColor: theme.colors.background, padding: theme.spacing.md, }, title: { color: theme.colors.text, fontSize: theme.fontSizes.lg, fontFamily: theme.typography.fontFamily.bold, }, button: { backgroundColor: theme.colors.primary, borderRadius: theme.components.borderRadius.md, padding: theme.spacing.sm, },}));
return ( <View style={styles.container}> <Text style={styles.title}>Hello World</Text> <TouchableOpacity style={styles.button}> <Text>Press Me</Text> </TouchableOpacity> </View>);}
Performance
Uses useMemo
to prevent unnecessary style recalculations, improving component performance.
Type Safe
Full TypeScript support with generic constraints ensuring type safety for style objects.
Theme Reactive
Automatically updates styles when theme changes, ensuring consistent UI across theme switches.
RN Compatible
Works seamlessly with React Native’s StyleSheet API and component styling patterns.
function ComplexCard({ title, subtitle, onPress }) {const styles = useThemedStyles((theme) => ({ card: { backgroundColor: theme.colors.surface, borderRadius: theme.components.borderRadius.lg, padding: theme.spacing.lg, marginVertical: theme.spacing.sm, shadowColor: theme.colors.shadow, shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: theme.spacing.md, }, title: { fontSize: theme.fontSizes.xl, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.text, }, subtitle: { fontSize: theme.fontSizes.sm, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, marginTop: theme.spacing.xs, }, button: { backgroundColor: theme.colors.primary, paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, borderRadius: theme.components.borderRadius.sm, }, buttonText: { color: theme.colors.onPrimary, fontSize: theme.fontSizes.sm, fontFamily: theme.typography.fontFamily.medium, },}));
return ( <View style={styles.card}> <View style={styles.header}> <View> <Text style={styles.title}>{title}</Text> <Text style={styles.subtitle}>{subtitle}</Text> </View> <TouchableOpacity style={styles.button} onPress={onPress}> <Text style={styles.buttonText}>Action</Text> </TouchableOpacity> </View> </View>);}
function ConditionalButton({ variant = 'primary', disabled = false, children }) {const styles = useThemedStyles((theme) => ({ button: { paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.md, borderRadius: theme.components.borderRadius.md, alignItems: 'center', justifyContent: 'center', }, primary: { backgroundColor: disabled ? theme.colors.disabled : theme.colors.primary, }, secondary: { backgroundColor: disabled ? theme.colors.disabled : theme.colors.secondary, borderWidth: 1, borderColor: theme.colors.border, }, outline: { backgroundColor: 'transparent', borderWidth: 1, borderColor: disabled ? theme.colors.disabled : theme.colors.primary, }, text: { fontSize: theme.fontSizes.md, fontFamily: theme.typography.fontFamily.medium, }, primaryText: { color: disabled ? theme.colors.textDisabled : theme.colors.onPrimary, }, secondaryText: { color: disabled ? theme.colors.textDisabled : theme.colors.onSecondary, }, outlineText: { color: disabled ? theme.colors.textDisabled : theme.colors.primary, },}));
return ( <TouchableOpacity style={[styles.button, styles[variant]]} disabled={disabled} > <Text style={[styles.text, styles[`${variant}Text`]]}> {children} </Text> </TouchableOpacity>);}
interface ProgressBarProps {progress: number; // 0-100height?: number;showLabel?: boolean;}
function ProgressBar({ progress, height = 8, showLabel = true }: ProgressBarProps) {const styles = useThemedStyles((theme) => ({ container: { width: '100%', marginVertical: theme.spacing.sm, }, track: { height, backgroundColor: theme.colors.surfaceVariant, borderRadius: height / 2, overflow: 'hidden', }, fill: { height: '100%', backgroundColor: theme.colors.primary, borderRadius: height / 2, width: `${Math.min(Math.max(progress, 0), 100)}%`, }, label: { fontSize: theme.fontSizes.sm, color: theme.colors.textSecondary, textAlign: 'center', marginTop: theme.spacing.xs, },}));
return ( <View style={styles.container}> <View style={styles.track}> <View style={styles.fill} /> </View> {showLabel && ( <Text style={styles.label}> {Math.round(progress)}% </Text> )} </View>);}
// ✅ Style factory defined outside component or memoizedconst createStyles = (theme) => ({container: { backgroundColor: theme.colors.background, padding: theme.spacing.md,},});
function OptimizedComponent() {const styles = useThemedStyles(createStyles);return <View style={styles.container} />;}
// ⚠️ Inline function recreated on every renderfunction ComponentWithInlineStyles() {const styles = useThemedStyles((theme) => ({ container: { backgroundColor: theme.colors.background, padding: theme.spacing.md, },}));return <View style={styles.container} />;}
// ✅ Use useCallback for dynamic style factoriesfunction DynamicComponent({ isActive }) {const createStyles = useCallback((theme) => ({ container: { backgroundColor: isActive ? theme.colors.primary : theme.colors.surface, opacity: isActive ? 1 : 0.6, },}), [isActive]);
const styles = useThemedStyles(createStyles);
return <View style={styles.container} />;}
import { StyleSheet } from 'react-native';import { Theme } from '../types/theme';
// Define your style typesinterface ButtonStyles {container: object;text: object;disabled: object;}
function TypedButton() {// Fully typed style factoryconst styles = useThemedStyles<ButtonStyles>((theme: Theme) => ({ container: { backgroundColor: theme.colors.primary, borderRadius: theme.components.borderRadius.md, padding: theme.spacing.md, }, text: { color: theme.colors.onPrimary, fontSize: theme.fontSizes.md, }, disabled: { backgroundColor: theme.colors.disabled, color: theme.colors.textDisabled, },}));
return ( <TouchableOpacity style={styles.container}> <Text style={styles.text}>Button</Text> </TouchableOpacity>);}
// Extend the theme type for custom propertiesinterface ExtendedTheme extends Theme {customColors: { brand: string; accent: string;};}
function ComponentWithCustomTheme() {const styles = useThemedStyles((theme: ExtendedTheme) => ({ container: { backgroundColor: theme.customColors.brand, borderColor: theme.customColors.accent, },}));
return <View style={styles.container} />;}
Define style factories outside components when possible to prevent unnecessary re-renders
Use useCallback for dynamic style factories that depend on props or state
Leverage TypeScript for better development experience and catch styling errors early
Keep style objects flat to maximize StyleSheet optimization benefits
Use semantic theme tokens rather than hardcoded values for better maintainability
Test theme switching to ensure styles update correctly across different themes
import { Dimensions } from 'react-native';
function ResponsiveCard() {const { width } = Dimensions.get('window');
const styles = useThemedStyles((theme) => ({ card: { backgroundColor: theme.colors.surface, borderRadius: theme.components.borderRadius.lg, padding: width > 768 ? theme.spacing.xl : theme.spacing.md, marginHorizontal: width > 768 ? theme.spacing.lg : theme.spacing.sm, }, title: { fontSize: width > 768 ? theme.fontSizes.xxl : theme.fontSizes.xl, color: theme.colors.text, },}));
return ( <View style={styles.card}> <Text style={styles.title}>Responsive Card</Text> </View>);}
import { Platform } from 'react-native';
function PlatformAwareComponent() {const styles = useThemedStyles((theme) => ({ container: { backgroundColor: theme.colors.background, padding: theme.spacing.md, ...Platform.select({ ios: { shadowColor: theme.colors.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, android: { elevation: 4, }, }), }, text: { fontSize: theme.fontSizes.md, fontFamily: Platform.select({ ios: theme.typography.fontFamily.regular, android: theme.typography.fontFamily.medium, }), color: theme.colors.text, },}));
return ( <View style={styles.container}> <Text style={styles.text}>Platform Aware Text</Text> </View>);}
Styles not updating on theme change
Cause: Style factory function reference changing on every render
Solution: Define style factory outside component or wrap with useCallback
Performance issues with complex styles
Cause: Heavy computations in style factory
Solution: Optimize style calculations or consider breaking into smaller components
TypeScript errors with style properties
Cause: Incorrect theme type or style property types
Solution: Ensure theme type matches your theme structure and use proper React Native style types