일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 생활코딩
- 코드스테이츠
- 카카오
- Til
- REST_API
- mysemester
- 큐
- javascript
- 30daysdowoonchallenge
- CSS
- vercel
- 자료구조
- 프로토타입
- useState
- UI
- web
- 회고
- React
- Next.js
- 백준
- html
- 운영체제
- redux
- 프로그래머스
- 해시테이블
- 자바스크립트
- UX
- 스택
- level1
- superstarjypnation
- Today
- Total
데굴데굴
TIL: 2023-06-09 Provider Pattern 본문
⚙️ 오늘 학습한 내용
Provider Pattern
🗝 키워드
Provider Pattern, Context API, ThemeProvider
🗣 스스로에게 설명
Patterns.dev에 설명된 내용을 기반으로 정리했습니다.
Provider Pattern
여러 자식 컴포넌트에서 데이터를 사용할 수 있게 한다
보통 데이터를 여러 컴포넌트에서 사용하고 싶은 경우 props를 이용할 수 있다.
props 전달이 깊어지게 되면 props drilling이 발생하게 되고 이는 코드의 유지보수를 어렵게 만든다.
props에 의존하지 않으면서 데이터를 필요로 하는 곳에만 쓸 수 있도록 해주는 방법이 필요한데 이 때 Provider Pattern을 적용할 수 있다.
Provider 만들기
리액트에서는 Context API의 createContext
를 이용하여 Provider를 만든다.
Provider의 value
속성에 데이터를 전달하고 Provider로 다른 컴포넌트를 감싸게 되면 props를 전달하지 않아도 하위 컴포넌트에서 값 접근이 가능해진다.
const DataContext = React.createContext();
function App() {
const data = {...};
return (
<div>
<DataContext.Provider value={data}>
<Sidebar />
<Content />
</DataContext.Provider>
</div>
)
}
각 컴포넌트에서 값의 접근이 가능하도록 할 때에는 useContext
를 사용한다.
(사이트에 설명된 코드에는 Provider로 감싸는 부분이 없는데, 오류인지 아닌지 잘 모르겠다.)
const DataContext = React.createContext();
function App() {
const data = { ... }
return (
<div>
<SideBar />
<Content />
</div>
)
}
const Sidebar = () => <List />
const List = () => <ListItem />
function ListItem() {
const { data } = React.useContext(DataContext);
return <span>{data.listItem}</span>
}
context를 쓰면 상관없는 컴포넌트에게는 데이터를 불필요하게 전달하지 않아도 된다.
Provider Pattern은 전역 데이터를 공유할 때 유용한데, 주로 테마 변경에 쓰인다.
provider-1 - CodeSandbox
provider-1 by lydiahallie using react, react-dom, react-scripts
codesandbox.io
여기에 그 예제가 있는데, 위는 아직 Provider Pattern 적용 전이다.
직접 바꿔보면서 연습해보면 좋을 것 같다.
Hook으로 간소화하기
만약 useContext
를 써야 하는 컴포넌트가 여러 개라면 같은 코드를 여러 번 작성하는 건 번거로운 일이 되기 때문에 custom Hook을 만들 수 있다.
function useThemeContext() {
const theme = useContext(ThemeContext);
if (!theme) {
throw new Error("useThemeContext must be used within ThemeProvider");
}
return theme;
}
ThemeContext.Provider
대신 전체 컴포넌트를 감싸는 HoC를 만들 수도 있다.
이렇게 하면 context 관련 로직을 컴포넌트 렌더링 코드에서 분리할 수가 있어 재사용성을 높일 수가 있다.
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("dark");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
const providerValue = {
theme: themes[theme],
toggleTheme
}
return (
<ThemeContext.Provider value={providerValue}>
{children}
</ThemeContext.Provider>
)
}
export default function App() {
return (
<div className={`App theme-${theme}`}>
<ThemeProvider>
<Toggle />
<List />
</ThemeProvider>
</div>
)
}
각 하위 컴포넌트에서의 값 접근은 useThemeContext
로 통일할 수 있다.
export default function ListItem() {
const theme = useThemeContext();
return <li style={theme.theme}>...</li>
}
사용 라이브러리
styled-components에 ThemeProvider
가 내장되어 있다.
styled-components로 만든 모든 컴포넌트는 이 provider에 접근이 가능하다.
import { ThemeProvider } from "styled-components";
export default function App() {
const [theme, setTheme] = useState("dark");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
return (
<div className={`App theme-${theme}`}>
<ThemeProvider theme={themes[theme]}>
<Toggle toggleTheme={toggleTheme} />
<List />
</ThemeProvider>
</div>
);
}
이 예제에서는 인라인 스타일 대신 styled-components로 li
요소를 만들어 테마에 따라 동적으로 스타일이 적용되도록 하고 있다.
import styled from 'styled-components';
export default function ListItem() {
return <Li>...</Li>
}
const Li = styled.li`
${({ theme }) => `
background-color: ${theme.backgroundColor},
color: ${theme.color};
`}
`
장단점
장점
props drilling에서 자유로워진다
데이터가 필요없는 컴포넌트에는 전달되지 않기 때문에 앱의 데이터 흐름 파악이 용이해진다
전역에서 접근이 가능하기 때문에 필요한 컴포넌트에서만 골라쓸 수가 있다
단점
과도하게 사용하면 성능이 저하된다
context를 사용하는 컴포넌트는 상태가 바뀔 때마다 리렌더링되기 때문이다
provider-4 - CodeSandbox
provider-4 by lydiahallie using moment, react, react-dom, react-scripts
codesandbox.io
여기에 관련 예제가 있다
Increment 버튼을 클릭하면 count가 증가하는데, 바로 밑에 있는 Reset Count 버튼에서도 `useCountContext`를 같이 사용하고 있기 때문에 Increment 버튼 클릭으로 인한 상태 변경에 영향을 받아 리셋 시간도 함께 바뀌는 것을 볼 수 있다.
불필요한 업데이트를 방지하려면 사용 목적에 맞게 provider를 잘 나눠서 만드는 것도 중요하다.
Provider Pattern
Make data available to multiple child components
www.patterns.dev
'Lesson > TIL' 카테고리의 다른 글
TIL: 2023-06-11 제어, 비제어 컴포넌트 (0) | 2023.06.11 |
---|---|
TIL: 2023-06-08 Proxy Pattern (0) | 2023.06.08 |
TIL: 2023-06-07 Singleton Pattern (0) | 2023.06.07 |
TIL: 2023-06-05 (0) | 2023.06.05 |
TIL: 2023-05-11 (0) | 2023.05.11 |