ダークモード切り替え付きTheme Context
現在のカラースキームを保持するThemeContextを構築し、切り替え関数を公開して、アプリ全体のコンポーネントにテーマカラーを適用します
「ダークモード切り替え付きTheme Context」はCoddyKit上の無料React Native Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これは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 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.
よくある質問
「ダークモード切り替え付きTheme Context」レッスンは無料ですか?
はい。「ダークモード切り替え付きTheme Context」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Native Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Native Academyコースには全4レッスンが含まれています。
「ダークモード切り替え付きTheme Context」で何を学びますか?
現在のカラースキームを保持するThemeContextを構築し、切り替え関数を公開して、アプリ全体のコンポーネントにテーマカラーを適用します ブラウザで直接実行するハンズオンコードでReact Native Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Native Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Native Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「ダークモード切り替え付きTheme Context」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Native Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Native Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Contextの作成と提供
- useContextによるContextの利用
- ダークモード切り替え付きTheme Context
- Contextによるパフォーマンス問題の回避