useContext 훅은 어떻게 사용할까?
리액트의 일반적인 데이터 흐름은 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 '단방향'으로 흐른다. 엄청 큰 컴포넌트 트리가 있다고 가정할 때 공통적으로 필요한 전역적인 데이터가 있을 수 있다. 예를 들어 userdata
전역 데이터를 일일이 props로 단계별로 전달해야 한다면 정말 비효율 적이다.
리액트는 이러한 문제점을 해결해 주는 Context API를 제공한다.
Context는 앱 안에서 전역적으로 사용되는 데이터를 여러 컴포넌트끼리 쉽게 공유할 수 있는 방법을 제공한다. Context를 사용하면 Props로 데이터를 일일이 전달해 주지 않아도 해당 데이터를 가지고 있는 상 위 컴포넌트에 그 데이터가 필요한 하위 컴포넌트가 접근할 수 있다. 즉 사용자 정보, 테마, 언어 등 전역적인 데이터를 전달하기에 정말 편리하다.
상위 컴포넌트의 data가 필요한 하위 컴포넌트들은 useContext 훅을 사용해서 해당 데이터를 받아오기만 하면 된다.
useContext는 Context로 분류한 데이터를 쉽게 받아올 수 있게 도와주는 역할을 한다.
Q. context가 이렇게 좋은데 그럼 굳이 왜 props를 사용하는가?
context는 꼭 필요할 때만 사용한다. context를 사용하면 컴포넌트를 재사용하기 어려워질 수 있다. context의 주된 목적인 다양한 레벨이 있는 많은 컴포넌트들에게 전역적인 데이터를 전달하기 위함이다.
// 최상위 컴포넌트
import { useState } from "react";
import "./App.css";
import Page from "./Compopnents/Page";
function App() {
// 햔제 App 이 다크모드인지 아닌지 true false 로 정보를 받고 있다.
const [isDark, setIsDark] = useState(false);
// Page 자식 컴포넌트에게 해당 데이터를 props로 넘겨 주고 있다.
return <Page isDark={isDark} setIsDark={setIsDark}/>
}
export default App;
🐓 Page 컴포넌트
// page 컴포넌트
import React, { useContext } from "react";
import Content from "./Context";
import Header from "./Header";
import Footer from "./Footer";
const Page = ({isDark, setIsDark}) => {
return (
<div className="page">
<Header isDark={isDark}/>
<Content isDark={isDark}/>
<Footer isDark={isDark} setIsDark={setIsDark}/>
</div>
);
};
export default Page;
- 전체화면을 담고 있는 컴포넌트
- 3개의 자식 컴포넌트를 가지고 있다.
- {isDark, setIsDark} 를 props로 받아오고 있다.
- isDark 를 모든 자식 컴포넌트에게 전달을 해주고, setIsDark는 Footer에게 전달해준다.
🐥 Header 컴포넌트
import React from "react";
const Header = ({ isDark }) => {
return (
<header
className="header"
style={{
backgroundColor: isDark ? "black" : "lightgray",
color: isDark ? "white" : "black",
}}
>
<h1>Welcome 홍길동</h1>
</header>
);
};
export default Header;
- isDark 를 props로 전달받고 있다.
- header 태그는 isDark가 true 이면 배경이 black, false면 lightgray 아래 글씨 색상도 동일하게 작동한다.
🐥 Content 컴포넌트
import React from "react";
const Content = ({ isDark }) => {
return (
<div
className="content"
style={{
backgroundColor: isDark ? "black" : "white",
color: isDark ? "white" : "black",
}}
>
<p>홍길동님, 좋은 하루 되세요 </p>
</div>
);
};
export default Content;
- isDark 를 props로 전달받고 있다.
- header 와 마찬가지고 isDark 가 true냐 false이냐에 따라 배경과 글자색상이 달라진다.
🐥 Footer 컴포넌트
import React from "react";
const Footer = ({ isDark, setIsDark }) => {
const toggleTheme = () => {
setIsDark(!isDark);
};
return (
<footer
className="footer"
style={{ backgroundColor: isDark ? "black" : "lightgray" }}
>
<button className="button" onClick={toggleTheme}>
Dark Mode
</button>
</footer>
);
};
export default Footer;
- isDark와 setIsDark를 props로 전달받고 있다.
- isDark 가 true냐 false이냐에 따라 배경과 글자색상이 달라진다.
- button 이 클릭될 때마다 toggleTheme 함수가 실행된다.
- toggleTheme 는 현재 isDark가 true 면 false로 바꿔주고 false 면 true 로 바꿔준다.
App 컴포넌트가 가지고 있는 isDark 데이터를 모든 하위 컴포넌트에게 props를 사용하지 않고 context를 사용해서 공유
react context를 만들려면 가장 먼저 createContext를 import 시켜줘야한다.
import { createContext } from "react";
// 기본값으로는 null을 넣어준다.
export const ThemeContext = createContext(null);
App 컴포넌트로 돌아가서 위 context를 import 시켜준다.
- 그리고 page 컴포넌트를 만들어준 context의 provider로 감싸준다.
- context의 provider는 value 라는 props를 받는데 이 안에는 전달하고자 하는 데이터를 넣어준다.
- ThemeContext 감싸는 모든 하위 컴포넌트는 props를 사용하지 않고 value로 넣어준 값에 접근할 수 있다. 그리고 페이지 컴포넌트가 갖는 값들을 지워준다.
import { useState } from "react";
import "./App.css";
import Page from "./Compopnents/Page";
import { ThemeContext } from "./context/ThemeContext";
function App() {
const [isDark, setIsDark] = useState(false);
return (
// 📌
<ThemeContext.Provider value={{ isDark, setIsDark }}>
<Page />
</ThemeContext.Provider>
);
}
export default App;
page 컴포넌트에서 인자로 받아오는 {isDark, setIsDark} 를 지워준다. 그리고 중간 컴포넌트이니 isDark와 가 필요가 없다.
import React from "react";
import Content from "./Context";
import Header from "./Header";
import Footer from "./Footer";
// isDark 를 실질적으로 사용하지 않고, 자녀 컴포넌트들에게 전달하는 역할
// data 필요하지 않음 !
const Page = () => {
return (
<div className="page">
<Header/>
<Content/>
<Footer/>
</div>
);
};
export default Page;
*****자식컴포넌트들에서 props 지워주기
header에서는 props를 지워주고 useContext 훅을 사용해 ThemeContext를 불러온다.
import { useContext } from "react";
// 📌
import { ThemeContext } from "../context/ThemeContext";
const Header = () => {
// 📌
const { isDark } = useContext(ThemeContext);
return (
<header
className="header"
style={{
backgroundColor: isDark ? "black" : "lightgray",
color: isDark ? "white" : "black",
}}
>
<h1>Welcome 홍길동!</h1>
</header>
);
};
export default Header;
import React, { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
const Content = () => {
// 📌
const { isDark } = useContext(ThemeContext);
return (
<div
className="content"
style={{
backgroundColor: isDark ? "black" : "white",
color: isDark ? "white" : "black",
}}
>
<p>홍길동님, 좋은 하루 되세요 </p>
</div>
);
};
export default Content;
import React, { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
const Footer = () => {
// 📌
const { isDark, setIsDark } = useContext(ThemeContext);
const toggleTheme = () => {
setIsDark(!isDark);
};
return (
<footer
className="footer"
style={{ backgroundColor: isDark ? "black" : "lightgray" }}
>
<button className="button" onClick={toggleTheme}>
Dark Mode
</button>
</footer>
);
};
export default Footer;
'React' 카테고리의 다른 글
[React]useCallback (0) | 2024.09.03 |
---|---|
[React] useMemo (2) | 2024.09.03 |
[React]useReducer (0) | 2024.08.20 |
[React] react-hook-form 사용하기 (0) | 2024.08.13 |
[React] react-hook-form useRef 사용 (0) | 2024.08.13 |