Un contexto de tema con alternancia del modo oscuro
Cree un ThemeContext que almacene el esquema de colores actual, exponga una función de alternancia y aplique los colores del tema a los componentes de toda la aplicación.
Un contexto de tema con alternancia del modo oscuro es una lección gratuita de React Native Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de React Native Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de React Native Academy incluye 4 lecciones en total.
Partes de esta lección aún no han sido traducidas y se muestran en inglés.
Why a Theme Context?
A theme context centralizes color and typography values so that every component in the app reads from a single source of truth. When the user switches between light and dark mode, updating the context value triggers a re-render of all consuming components with the new colors — no prop drilling or manual updates required.
Defining Light and Dark Theme Objects
Start by defining two theme objects with the same keys. Using identical keys for both themes means every component can apply a color without knowing which mode is active — it just reads from the current theme object and both themes handle the rest.
export const lightTheme = {
background: '#ffffff',
text: '#1a1a2e',
card: '#f5f5f5',
primary: '#6200ee',
border: '#e0e0e0',
};
export const darkTheme = {
background: '#1a1a2e',
text: '#e8e8f0',
card: '#16213e',
primary: '#bb86fc',
border: '#333355',
};Creating the ThemeContext
Create a ThemeContext that holds the current theme object and a toggle function. The default value mirrors the shape of what the Provider will supply, making it safe to destructure in consumers even if the Provider is accidentally missing in tests.
import { createContext, useContext, useState } from 'react';
import { lightTheme, darkTheme } from './themes';
export const ThemeContext = createContext({
theme: lightTheme,
isDark: false,
toggleTheme: () => {},
});Building the ThemeProvider
The ThemeProvider manages a boolean isDark state and derives the active theme object from it. The toggleTheme function flips the boolean. Memoize the context value with useMemo so that a new object reference is only created when isDark actually changes.
export function ThemeProvider({ children }) {
const [isDark, setIsDark] = useState(false);
const value = useMemo(() => ({
theme: isDark ? darkTheme : lightTheme,
isDark,
toggleTheme: () => setIsDark((d) => !d),
}), [isDark]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}A useTheme Custom Hook
Export a useTheme hook that wraps useContext(ThemeContext). Components call useTheme() for a clean, descriptive import instead of remembering to pass the context object. The hook also throws a helpful error if called outside a ThemeProvider.
export function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error('useTheme must be inside ThemeProvider');
return ctx;
}Applying Theme Colors to a Component
Any component that reads from useTheme will automatically display the correct colors for the current mode. Pass the theme colors into inline styles or StyleSheet styles. When the theme toggles, all consuming components re-render with the new values.
function Card({ title, body }) {
const { theme } = useTheme();
return (
<View style={{
backgroundColor: theme.card,
borderColor: theme.border,
borderWidth: 1,
borderRadius: 8,
padding: 16,
}}>
<Text style={{ color: theme.text, fontWeight: 'bold' }}>{title}</Text>
<Text style={{ color: theme.text }}>{body}</Text>
</View>
);
}A Toggle Switch in the Settings Screen
Add a dark mode switch to the settings screen. The Switch component's value is isDark from the theme context, and onValueChange calls toggleTheme. No local state needed — the toggle directly controls the global theme state.
function SettingsScreen() {
const { isDark, toggleTheme, theme } = useTheme();
return (
<View style={{ backgroundColor: theme.background, flex: 1, padding: 24 }}>
<Text style={{ color: theme.text }}>Dark Mode</Text>
<Switch
value={isDark}
onValueChange={toggleTheme}
trackColor={{ true: theme.primary }}
/>
</View>
);
}Persisting the Theme Preference
Save the user's theme preference to AsyncStorage so it survives app restarts. In ThemeProvider, load the saved preference in a useEffect on mount and initialize state accordingly. Save the new value in toggleTheme whenever the user switches modes.
export function ThemeProvider({ children }) {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
AsyncStorage.getItem('theme').then((saved) => {
if (saved === 'dark') setIsDark(true);
});
}, []);
const toggleTheme = () => {
const next = !isDark;
setIsDark(next);
AsyncStorage.setItem('theme', next ? 'dark' : 'light');
};
// ...
}Respecting the System Theme
React Native's useColorScheme hook returns the device's current color scheme ('light' or 'dark'). You can use this as the default theme instead of always starting in light mode. If the user has not explicitly set a preference, respecting the system setting gives the best out-of-the-box experience.
import { useColorScheme } from 'react-native';
function ThemeProvider({ children }) {
const systemScheme = useColorScheme();
const [isDark, setIsDark] = useState(systemScheme === 'dark');
// ...
}Applying Theme to Navigation Header
The navigation header can also respond to theme changes. Pass a function to screenOptions on the navigator that reads from the theme context and returns header style options. When the theme changes, the navigator re-evaluates the options and updates the header colors accordingly.
function AppStack() {
const { theme } = useTheme();
return (
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: theme.card },
headerTintColor: theme.text,
}}
>
<Stack.Screen name='Home' component={HomeScreen} />
</Stack.Navigator>
);
}Preventing Flicker on Theme Load
When loading the saved theme from AsyncStorage on startup, there is a brief moment before the preference is restored. Prevent a flash of the wrong theme by showing a splash screen or delaying navigation until the theme is loaded. Use an isThemeReady state in the provider and render null until it is true.
const [isDark, setIsDark] = useState(false);
const [ready, setReady] = useState(false);
useEffect(() => {
AsyncStorage.getItem('theme').then((saved) => {
if (saved === 'dark') setIsDark(true);
setReady(true);
});
}, []);
if (!ready) return null; // prevent flashQuick Check
Test your understanding of theme context and dark mode from this lesson.
Lesson Recap
In this lesson you learned: define separate light and dark theme objects with matching keys, provide both the active theme and a toggleTheme function through context, and persist the theme preference to AsyncStorage and restore it on app startup. Next up we explore avoiding context performance pitfalls.
Preguntas frecuentes
¿La lección «Un contexto de tema con alternancia del modo oscuro» es gratis?
Sí — el texto completo de «Un contexto de tema con alternancia del modo oscuro» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de React Native Academy, actualiza a CoddyKit PRO. El curso de React Native Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Un contexto de tema con alternancia del modo oscuro»?
Cree un ThemeContext que almacene el esquema de colores actual, exponga una función de alternancia y aplique los colores del tema a los componentes de toda la aplicación. Practicas React Native Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar React Native Academy?
No se requiere experiencia previa. React Native Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Un contexto de tema con alternancia del modo oscuro»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de React Native Academy?
Sí. Cada lección de React Native Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Creación y provisión de un contexto
- Consumo de contexto con useContext
- Un contexto de tema con alternancia del modo oscuro
- Cómo evitar problemas de rendimiento del contexto