0Pricing
React Native Academy · درس

‏Theme Context مع مفتاح الوضع الداكن

أنشئ ThemeContext يخزّن نظام الألوان الحالي، وأتِح دالة للتبديل، وطبّق ألوان السمة على المكوّنات في أنحاء التطبيق.

‏Theme Context مع مفتاح الوضع الداكن درس مجاني في React Native Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في React Native Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة React Native Academy 4 دروس في المجموع.

بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.

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 flash

Quick 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.

الأسئلة الشائعة

هل درس «‏Theme Context مع مفتاح الوضع الداكن» مجاني؟

نعم — نص درس «‏Theme Context مع مفتاح الوضع الداكن» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة React Native Academy، انتقل إلى CoddyKit PRO. تتضمن دورة React Native Academy 4 دروس في المجموع.

ماذا ستتعلم في «‏Theme Context مع مفتاح الوضع الداكن»؟

أنشئ ThemeContext يخزّن نظام الألوان الحالي، وأتِح دالة للتبديل، وطبّق ألوان السمة على المكوّنات في أنحاء التطبيق. تتمرن على React Native Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ React Native Academy؟

لا تُشترط خبرة سابقة. React Native Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «‏Theme Context مع مفتاح الوضع الداكن»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس React Native Academy هذا؟

نعم. كل درس في React Native Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. إنشاء Context وتوفيره
  2. استهلاك Context باستخدام useContext
  3. ‏Theme Context مع مفتاح الوضع الداكن
  4. تجنب مشكلات أداء Context
← العودة إلى React Native Academy