React에서는 상태를 전역적으로 관리하고, 여러 컴포넌트 간에 데이터를 쉽게 공유할 수 있는 방법을 제공합니다. 그 중 하나가 Context API입니다. Context API를 사용하면, 상태를 부모 컴포넌트에서 자식 컴포넌트로 props로 전달하지 않고도, 전역적으로 데이터를 관리하고 사용할 수 있습니다.
이번 포스트에서는 테마를 전역 상태로 관리하는 예제를 통해 useContext 훅을 사용하는 방법을 소개합니다.
Context API 사용법
- Context 생성: React.createContext()를 사용하여 Context 객체를 생성합니다.
- Provider 정의: Context.Provider를 사용하여 하위 컴포넌트들에게 값을 제공(전달)합니다.
- Context 소비: useContext 훅을 사용하여 Context의 값을 하위 컴포넌트에서 소비(사용)합니다.
예제: 테마를 적용한 페이지
1. 테마 전환 버튼
우리는 먼저 사용자가 클릭할 수 있는 버튼을 만들어, 테마를 변경할 수 있도록 할 것입니다. 여기서는 light와 dark 테마 두 가지를 지원하며, 테마에 맞는 스타일을 적용합니다.
2. Blog, News 컴포넌트
블로그와 뉴스 컴포넌트에서는 현재 테마에 맞춰 스타일을 동적으로 변경합니다.
1단계: 테마를 전역적으로 관리하기 위한 ThemeContext 생성
먼저 ThemeContext를 생성하여 테마 상태를 전역에서 사용할 수 있게 합니다.
import { createContext, useContext, useState } from "react";
// 테마에 맞는 스타일을 반환하는 함수
// theme이 'light'일 경우 배경색은 흰색(#fff), 텍스트 색은 검정(#000)으로 반환
// theme이 'dark'일 경우 배경색은 어두운 회색(#333), 텍스트 색은 흰색(#fff)으로 반환
const getThemedStyle = theme => ({
backgroundColor: theme === "light" ? "#fff" : "#333", // 테마에 따라 배경색 변경
color: theme === "light" ? "#000" : "#fff" // 테마에 따라 글자색 변경
});
// Context 생성: 테마와 테마 변경 기능을 공유하기 위해 Context를 생성
const ThemeContext = createContext();
// Provider 정의: 자식 컴포넌트에 테마 정보와 테마 변경 함수를 제공하는 컴포넌트
const ThemeProvider = ({ children }) => {
// 현재 테마 상태를 관리하는 useState 훅
const [theme, setTheme] = useState('light'); // 초기값은 'light'
// 테마를 변경하는 함수 (현재 테마가 'light'이면 'dark'로, 'dark'이면 'light'로 변경)
const changeTheme = () => setTheme(theme === "light" ? "dark" : "light");
return (
// ThemeContext.Provider를 사용해 자식 컴포넌트에게 테마 정보와 테마 변경 함수 전달
<ThemeContext.Provider value={{ theme, changeTheme }}>
{children}
</ThemeContext.Provider>
);
};
- createContext()를 사용하여 ThemeContext를 생성합니다.
- ThemeProvider는 theme 상태와 이를 변경하는 changeTheme 함수를 ThemeContext.Provider를 통해 자식 컴포넌트에 전달합니다.
2단계: useContext로 테마 소비하기
각 컴포넌트에서 useContext(ThemeContext)를 사용하여 theme 값을 소비하고, 이를 기반으로 스타일을 변경합니다.
ThemedButton 컴포넌트
const ThemedButton = () => {
// useContext 훅을 사용하여 ThemeContext에서 현재 테마(theme)와 테마 변경 함수(changeTheme)를 가져옴
const { theme, changeTheme } = useContext(ThemeContext);
return (
// 버튼 클릭 시 changeTheme 함수가 실행되어 테마가 변경됨
// 버튼의 스타일은 getThemedStyle 함수로 현재 테마에 맞게 적용됨
<button onClick={changeTheme} style={getThemedStyle(theme)}>
테마 변경
</button>
);
};
- useContext(ThemeContext)를 사용해 theme과 changeTheme를 가져옵니다.
- 버튼을 클릭하면 changeTheme가 호출되어 테마가 변경됩니다.
Blog 컴포넌트
const Blog = () => {
// useContext 훅을 사용하여 ThemeContext에서 현재 테마(theme)를 가져옴
const { theme } = useContext(ThemeContext);
return (
// div의 스타일을 getThemedStyle 함수로 현재 테마에 맞게 적용
<div style={getThemedStyle(theme)}>
<h1>블로그</h1>
{/* 블로그 내용 */}
<p>헌법개정안이 제2항의 찬성을 얻은 때에는 헌법개정은 확정되며, 대통령은 즉시 이를 공포하여야 한다.</p>
<p>대법원장의 임기는 6년으로 하며, 중임할 수 없다. 정당의 설립은 자유이며, 복수정당제는 보장된다.</p>
</div>
);
};
- useContext(ThemeContext)를 사용하여 theme 값을 가져와 스타일을 동적으로 변경합니다.
News 컴포넌트
const News = () => {
// useContext 훅을 사용하여 ThemeContext에서 현재 테마(theme)를 가져옴
const { theme } = useContext(ThemeContext);
return (
// div의 스타일을 getThemedStyle 함수로 현재 테마에 맞게 적용
<div style={getThemedStyle(theme)}>
<h1>뉴스</h1>
{/* 뉴스 내용 */}
<p>국군의 조직과 편성은 법률로 정한다. 군인은 현역을 면한 후가 아니면 국무위원으로 임명될 수 없다.</p>
<p>모든 국민은 법률이 정하는 바에 의하여 공무담임권을 가진다.</p>
</div>
);
};
- useContext(ThemeContext)를 사용하여 테마 값을 받아와 해당 테마에 맞는 스타일을 적용합니다.
3단계: App 컴포넌트에서 ThemeProvider 적용
마지막으로 ThemeProvider를 최상위 컴포넌트에 적용하여, 하위 컴포넌트들에서 테마를 사용할 수 있도록 합니다.
const App = () => {
return (
// ThemeProvider로 전체 앱을 감싸서 하위 컴포넌트들이 테마를 공유하도록 함
<ThemeProvider>
{/* 페이지 제목 */}
<h1>테마가 적용된 페이지</h1>
{/* 테마 변경 버튼 */}
<ThemedButton />
{/* 테마가 적용된 블로그 콘텐츠 */}
<Blog />
{/* 테마가 적용된 뉴스 콘텐츠 */}
<News />
</ThemeProvider>
);
};
아래는 이를 모두 정리하 전체 코드입니다.
import { createContext, useContext, useState } from "react";
// 테마에 맞는 스타일을 반환하는 함수
// 'light' 테마일 경우 배경색을 흰색(#fff), 글자색을 검정색(#000)으로 설정
// 'dark' 테마일 경우 배경색을 어두운 회색(#333), 글자색을 흰색(#fff)으로 설정
const getThemedStyle = theme => ({
backgroundColor: theme === "light" ? "#fff" : "#333", // 테마에 따른 배경색
color: theme === "light" ? "#000" : "#fff" // 테마에 따른 글자색
});
// ThemeContext 생성: 테마 정보와 테마 변경 기능을 공유하기 위한 Context
const ThemeContext = createContext();
// ThemeProvider 컴포넌트 정의: 자식 컴포넌트에 테마와 테마 변경 함수를 제공
const ThemeProvider = ({ children }) => {
// 테마 상태를 관리하는 useState 훅, 초기값은 'light'
const [theme, setTheme] = useState('light');
// 테마를 'light'와 'dark' 사이에서 전환하는 함수
const changeTheme = () => setTheme(theme === "light" ? "dark" : "light");
return (
// ThemeContext.Provider로 자식 컴포넌트에게 theme과 changeTheme을 제공
<ThemeContext.Provider value={{ theme, changeTheme }}>
{children} {/* 자식 컴포넌트를 렌더링 */}
</ThemeContext.Provider>
);
};
// ThemedButton 컴포넌트: 테마를 변경하는 버튼
const ThemedButton = () => {
// useContext로 ThemeContext에서 테마와 테마 변경 함수를 가져옴
const { theme, changeTheme } = useContext(ThemeContext);
return (
// 버튼 클릭 시 changeTheme 함수가 호출되어 테마가 변경됨
// 버튼 스타일은 현재 테마에 맞게 적용
<button onClick={changeTheme} style={getThemedStyle(theme)}>
테마 변경
</button>
);
};
// Blog 컴포넌트: 블로그 콘텐츠와 테마 적용
const Blog = () => {
// useContext로 ThemeContext에서 현재 테마를 가져옴
const { theme } = useContext(ThemeContext);
return (
// 블로그 콘텐츠에 테마 스타일을 적용
<div style={getThemedStyle(theme)}>
<h1>블로그</h1>
{/* 블로그 내용 */}
<p>헌법개정안이 제2항의 찬성을 얻은 때에는 헌법개정은 확정되며, 대통령은 즉시 이를 공포하여야 한다.</p>
<p>대법원장의 임기는 6년으로 하며, 중임할 수 없다. 정당의 설립은 자유이며, 복수정당제는 보장된다.</p>
</div>
);
};
// News 컴포넌트: 뉴스 콘텐츠와 테마 적용
const News = () => {
// useContext로 ThemeContext에서 현재 테마를 가져옴
const { theme } = useContext(ThemeContext);
return (
// 뉴스 콘텐츠에 테마 스타일을 적용
<div style={getThemedStyle(theme)}>
<h1>뉴스</h1>
{/* 뉴스 내용 */}
<p>국군의 조직과 편성은 법률로 정한다. 군인은 현역을 면한 후가 아니면 국무위원으로 임명될 수 없다.</p>
<p>모든 국민은 법률이 정하는 바에 의하여 공무담임권을 가진다.</p>
</div>
);
};
// App 컴포넌트: ThemeProvider로 앱을 감싸고, 테마가 적용된 여러 컴포넌트를 렌더링
const App = () => {
return (
// ThemeProvider로 자식 컴포넌트들이 테마 정보를 사용할 수 있도록 함
<ThemeProvider>
<h1>테마가 적용된 페이지</h1>
{/* 테마 변경 버튼 */}
<ThemedButton />
{/* 블로그 콘텐츠 */}
<Blog />
{/* 뉴스 콘텐츠 */}
<News />
</ThemeProvider>
);
};
// App 컴포넌트를 내보냄
export default App;
Context API와 useContext 훅을 사용하면 전역 상태를 쉽게 관리할 수 있으며, props 전달을 복잡하게 하지 않고도 여러 컴포넌트에 데이터를 공유할 수 있습니다. 위 예제에서는 테마를 Context로 관리하여, 테마 변경 시 각 컴포넌트에서 쉽게 스타일을 업데이트할 수 있도록 했습니다.
*생성형 AI 활용한 클라우드&보안 전문가 양성캠프 과정의 교육내용 정리 자료입니다.
'코딩 > 리액트' 카테고리의 다른 글
[새싹 성동 2기] React Router 부가 기능(네비게이션, 스타일링, 리다이렉션) (0) | 2024.12.06 |
---|---|
[새싹 성동 2기] 리액트 라우터와 사용예시 (2) | 2024.12.06 |
[새싹 성동 2기] useMemo, useCallback, React.memo 활용법 (1) | 2024.12.06 |
[새싹 성동 2기] useReducer를 활용한 상태 관리 (0) | 2024.12.06 |
[새싹 성동 2기] 리액트 앱에서 국가와 국기 정보를 출력하는 방법 (1) | 2024.11.19 |