다크 모드 전환이 있는 테마 컨텍스트
현재 색 구성표를 저장하는 ThemeContext를 만들고 전환 함수를 노출하며 앱 전체의 컴포넌트에 테마 색상을 적용합니다.
다크 모드 전환이 있는 테마 컨텍스트은(는) CoddyKit의 무료 React Native Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 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.
자주 묻는 질문
“다크 모드 전환이 있는 테마 컨텍스트” 강의는 무료인가요?
네 — “다크 모드 전환이 있는 테마 컨텍스트” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Native Academy 강의 전체를 잠금 해제할 수 있습니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“다크 모드 전환이 있는 테마 컨텍스트”에서 뭘 배우나요?
현재 색 구성표를 저장하는 ThemeContext를 만들고 전환 함수를 노출하며 앱 전체의 컴포넌트에 테마 색상을 적용합니다. 브라우저에서 직접 실행하는 실습 코드로 React Native Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
React Native Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 React Native Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“다크 모드 전환이 있는 테마 컨텍스트” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 React Native Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 React Native Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 컨텍스트 만들고 제공하기
- useContext로 컨텍스트 사용하기
- 다크 모드 전환이 있는 테마 컨텍스트
- 컨텍스트 성능 문제 피하기