Props Drilling
정말 정말 정말 해결하고 싶은 문제.
사용하지 않는 컴포넌트에서, 단지 전달해주기 위해 props를 다 적어줘야 하는데, 이를 피하기 위해 state를 전역적으로 관리를 하는 redux, react-query등이 있고 props drilling을 회피하기 위해 ContextAPI를 사용해 볼 수도 있다.
ContextAPI는 전역적으로 관리하기 보다는 목적이 props drilling 피하기 위한 것. ContextAPI는 전달만 해주더라도 랜더링이 일어나기 때문에 랜더링 최적화를 위해서는 redux등을 이용한다고 한다.
그리고 redux, react-query 등의 패키지를 사용하기 위해서는 설치해야 하고.. 또 아직 규모가 작은 프로젝트에서 활용할 것이기 때문에 일단 ContextAPI에 대해 익숙해지려고 한다.
기본적인 내용이지만, 익숙하지 않으면 어려워보이기 때문에 예제를 다 본 다음, 한줄씩 떠올리면서 코드를 작성했다.
작성하면서 들었던 궁금증 목록
1. createContext, useContext는 각각 어떤 컴포넌트에서 호출되는 걸까?
(1) cerateContext는 따로 모듈화가 가능한 글을 읽었다. 그러면 Provider를 생성하는 건 <App/> 컴포넌트일까?
- 일단 Context를 모듈화 한다.
- Provider를 사용할 컴포넌트에 Context를 import해서 사용한다.
- useComsumer를 사용할 컴포넌트에 import Context해서 Context를 불러와 props를 사용하면 된다.
//src/context/MyContext
import { createContext } from "react";
export const MyContext = createContext(null);
.
//src/App
import { MyContext } from "./context/MyContext";
import Information from "./Information";
export default function App() {
return (
<div>
<MyContext.Provider value={{ info: "hello-kk" }}>
<Information />
</MyContext.Provider>
</div>
);
}
.
//src/Information
import React, { useContext } from "react";
import { MyContext } from "./context/MyContext";
function Information() {
const value = useContext(MyContext);
return <div>{value.info}</div>;
}
export default Information;
2. Provider는 부모 컴포넌트에서 한번만 하면 되는건가?
- 하위 컴포넌트에서 다른 value를 사용하길 바란다면 Provider 필요
3. createContext에 어떤 인자가 필요하지?
- 전달할 default props
(1) 그런데, 여기서도 의아했던 부분이 그러면 왜 MyContext.Provider에서 value 값을 채워야 하는걸까?
- useContext할 때 Provider가 상위에 없다면 default value를 사용한다고 한다. 와 이해하기 어려웠다. 왜냐면, Provider를 무조건 쓴다고 생각했으니까. 하지만 이렇게 모듈화로 따로 분리한다면 확실히 안쓰이게 되지만 useContext를 호출할 수 도 있는 상황이 있을수도 있을 것 같은데 정확한 사례는 찾아보진 못했다.
<MyContext.Provider value={ 객체 }>
...
<MyContext.Provider/>
4. useContext에 어떤 인자가 필요하지?
- Context(Provider)
5. createContext가 리턴하는 건?
- Context(Provider)
6. useContext가 리턴하는 건?
- 객체(props)
7. value를 안 적으면?
- 꼭 value를 사용해야 한다. default value를 적어주기 때문에 value를 쓰지 않아도 되는게 아닌가? 했는데, default value는 안전장치이기도 하고.. value를 적어주지 않으면 오류가 발생한다.
8. useContext()를 안한다면?
- class형에서는 <MyContext.Consumer>를 통해 값을 받아오는 예제들을 많이 봤다.
<MyContext.Consumer>
{state => ... }
</MyContext.Consumer>
9. 꼭 value라면 value로 이름이 같아야 하나?
- 일반적으로 이렇게 쓰이는것 같은데, return되는건 value안에 든 값이기 때문에 다른 변수명을 사용해도 작동한다.
import React, { useContext } from "react";
import { MyContext } from "./context/MyContext";
function Information() {
const a = useContext(MyContext);
console.log(a);
return <div>{a.info}</div>;
}
export default Information;
10. createContext랑 useContext랑 같은가?
- 아님. 매개변수와 리턴이 다르다. (서로 반대 느낌..)
11. Provider로 다음처럼 props를 전달할때, App 컴포넌트 안의 h1은 일단 영향을 받지 않는다. 직접 value 변수명으로 전달했어도 일단 <App/> 컴포넌트에서는 value를 사용할 수가 없다.
const themeContext = createContext({ color: "red" });
export default function App() {
const theme = useContext(themeContext);
return (
<themeContext.Provider value={{ color: "blue" }}>
<h1 style={theme}>Hello-kk</h1>
{/* red? blue? */}
<Sub1 />
</themeContext.Provider>
);
}
12. 전달 value들이 여러개면?
- 객체로 전달한다.
13. 꼭 value라는 변수명으로 전달 해야 하나?
- 공식 문서에서는 다음과 같이 설명하고 있다.
Provider 컴포넌트는 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달합니다.
14. 하위 컴포넌트
(1) Context.Provider로 직접 감싸지지 않은 경우(여기선 모듈화를 한 경우를 의미한다.)
=> useContext로 value를 그대로 사용할 수 있다.
const value = useContext(themeContext);
(만약 themeContext가 모듈화되어 export 가능한가? 아니면 어떻게 ..? )
예제에서는, createContext(default value)으로 할당했는데,useContext()를 createContext()를 하면 value 없이 Provider를 생성할 수 있고, 다음처럼 props를 전달할 수 있다. 하지만 모듈화를 한다면 default value를 꼭 적어주어야 한다는 오류 메시지를 볼 수 있다.
const tmpContext = createContext()
<tmpContext.Provider value={ 객체 }>
<Sub />
<tmpContext.Provider>
15. 사용할 곳에서 StoreContext를 import 한 뒤, <StoreContext.Consumer> 또는 useContext(StoreContext)
- Consumer보다 useContext()가 직관적이고, Consumer는 class형 컴포넌트, useContext는 함수형 컴포넌트에서 훅으로 주로 사용하는 예제들을 많이 봤다.
import StoreContext from "경로";
<StoreContext.Comsumer>
{store => store.속성 }
</StoreContext.Comsumer>
useContext의 경우 context.Consumer 없이도 컨텍스트를 활용 가능.
단순하게
import StoreContext from "경로";
const store = useContext(StoreContext)
{store => store.속성 }
16. 여기서 궁금한건, 기본 값이 든 context를 생성했는데, value를 왜 또 지정해줘야 하는 걸까? 사용할수가 없으면 왜 default 값을 줄 수 있는거지?
- 3번 에 기록해두었다.
const dfuContext = createContext({ color: "yellow" });
return (
<div>
<dfuContext.Provider>
<Sub3 />
</dfuContext.Provider>
</div>
);
https://beta.reactjs.org/reference/react/createContext
검색: create context default value
defaultValue는 오직(!) 컴포넌트가 트리 상에서 어떠한 Provider와도 매칭되지 않을때 사용된다.
구성 요소를 래핑하지 않고 격리된 상태에서 테스트하는 데 유용할 수 있습니다.
=> 3번에 적어놓음.
기본적으로는 <defaultContext.Provider value={}>로 전달해야 하는 것 같다
'Front-End > React.js' 카테고리의 다른 글
커스텀 훅 (0) | 2023.03.14 |
---|---|
프로젝트 디렉토리 구조 (0) | 2023.03.13 |
컴포넌트 모듈화 - Router 컴포넌트 모듈화부터 (1) | 2023.03.12 |
import 자동완성 (0) | 2023.03.10 |
컴포넌트 리렌더링 방지하기! React.memo (0) | 2023.03.06 |