ExpoStartup
Theming

ThemeContext

The React Context that manages theme state throughout the application.

ThemeContext

The ThemeContext provides theme state management throughout the app, allowing components to access and update the current theme (light or dark mode).

How It Works

ThemeContext is implemented using React's Context API and works with NativeWind's useColorScheme hook to manage and sync the theme state. The context provides:

  1. Access to the current theme mode (light/dark)
  2. A function to toggle between modes
  3. Automatic application of theme styles through NativeWind

Usage

Accessing Theme State

import { useTheme } from '@/app/contexts/ThemeContext';
 
function MyComponent() {
  const { isDark, toggleTheme } = useTheme();
  
  return (
    <View>
      <ThemedText>
        Current theme: {isDark ? 'Dark Mode' : 'Light Mode'}
      </ThemedText>
      <Button title="Toggle Theme" onPress={toggleTheme} />
    </View>
  );
}

Conditional Rendering Based on Theme

import { useTheme } from '@/app/contexts/ThemeContext';
 
function ThemedComponent() {
  const { isDark } = useTheme();
  
  return (
    <View className="p-4">
      {isDark ? (
        <Icon name="Moon" size={24} />
      ) : (
        <Icon name="Sun" size={24} />
      )}
      
      <ThemedText>
        This component renders differently based on the theme
      </ThemedText>
    </View>
  );
}

ThemeProvider Setup

The ThemeProvider component should wrap your application root to make theme functionality available throughout the app. This is already set up in the _layout.tsx file:

// From _layout.tsx
import { ThemeProvider } from '@/app/contexts/ThemeContext';
 
export default function RootLayout() {
  return (
    <ThemeProvider>
      <App />
    </ThemeProvider>
  );
}

Implementation Details

The ThemeContext is implemented in app/contexts/ThemeContext.tsx and includes:

import React, { createContext, useContext, useState } from 'react';
import { useColorScheme } from 'nativewind';
 
type ThemeContextType = {
  isDark: boolean;
  toggleTheme: () => void;
};
 
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
 
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
  const { colorScheme, toggleColorScheme } = useColorScheme();
  const [isDark, setIsDark] = useState(colorScheme === 'dark');
 
  const toggleTheme = () => {
    toggleColorScheme();
    setIsDark(!isDark);
  };
 
  return (
    <ThemeContext.Provider value={{ isDark, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
 
export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
};

The key elements are:

  1. ThemeContext: The React context that holds theme state
  2. ThemeProvider: Component that provides the context to the app
  3. useTheme: Custom hook for easy access to theme state and functions
  4. Integration with NativeWind's useColorScheme hook

Advanced Usage

Using with TypeScript

The context provides TypeScript types for better development experience:

import { useTheme } from '@/app/contexts/ThemeContext';
 
// TypeScript will infer the correct types
function ThemedButton() {
  const { isDark, toggleTheme } = useTheme();
  
  return (
    <Button 
      title={`Switch to ${isDark ? 'Light' : 'Dark'} Mode`}
      onPress={toggleTheme}
    />
  );
}

Persisting Theme Preference

The current implementation does not persist theme preferences. If you want to add this functionality, you could extend the ThemeContext to use AsyncStorage:

// Example modification for persistence
import AsyncStorage from '@react-native-async-storage/async-storage';
 
export const ThemeProvider = ({ children }) => {
  // Initialization code would check AsyncStorage
  // Toggle would save to AsyncStorage
  
  // ... implementation
};

On this page