a React Hook that lets you read and subscribe to context from your component
context란?
리액트 어플리케이션은 기본적으로 부모 컴포넌트와 자식 컴포넌트로 이뤄진 트리 구조를 갖고 있습니다.
그래서 부모가 가지고 있는 데이터를 자식에서도 사용하고 싶다면 props로 데이터를 넘겨줘야 합니다.
전달해야 하는 데이터가 있는 컴포넌트와 전달받아야 하는 컴포넌트의 거리가 멀어질수로 코드는 복잡해집니다.
그리고 그렇게 계속 넘겨주는 기법을 props drilling 이라고 합니다.
이러한 prop 내려주기를 극복하기 위해 등장한 개념이 context입니다.
context를 사용하면 명시적인 props 전달 없이도 선언한 하위 컴포넌트 모두에서 자유롭게 원하는 값을 사용할 수 있습니다.
Context lets the parent component make some information available to any component in the tree below it—no matter how deep—without passing it explicitly through props.
출처 - React 공식문서
const Context = createContext<{hello:string}>()
function ParentComponent () {
return (
<Context.Provider value={{hello:’react’}}>
<Context.Provider value={{hello :’ javascript ’}}>
<ChildComponent/>
</Context.Provider>
</Context.Provider>
)
}
function ChildComponent(){
const value = useContext(Context)
return <>{ value ? value.hello : ‘ ’ }</> // ‘javascript’ 반환
}
useContext를 사용하면 상위 컴포넌트 어딘가에서 선언된 <Context.Provider/>에서 제공한 값을 사용할 수 있게 된다.
만약, 여러 개의(같은Context의) Provider가 있다면 가장 가까운 Provider의 값을 가져오게 된다.
createContext로 만들어진 각각의 Context는 서로 독립적입니다.
different React contexts don’t override each other.
Each context that you make with createContext() is completely separate from other ones,
and ties together components using and providing that particular context.
One component may use or provide many different contexts without a problem.
출처 - 리액트 공식문서
에러를 방지하려면 useContext 내부에서 해당 콘텍스트가 존재하는 환경인지,
즉 콘텍스트가 한 번이라도 초기화되어 값을 내려주고 있는지 확인하면 된다.
const MyContext = createContext<{hello:string} | undefined>(undefined)
function ContextProvider({children, text}){
return <MyContext.Provider value={ {hello:’text’} }>{children}</MyContext.Provider>
}
function useMyContext(){
const context = useContext(MyContext)
if(context === undefined){
throw new Error(
‘ useMyContext는 ContextProvider 내부에서만 사용할 수 있습니다. ‘
)
}
}
//타입이 명시되어 있어서 굳이 ChildComponent에서 undefined를 체크하지 않아도 된다.
다수의 Provider와 useContext를 사용할 때, 위와 같이 별도 함수로 감싸서 사용하는 것이 좋다. 타입 추론에도 유용하고, 상위에
Provider가 없는 경우에도 사전에 쉽게 에러를 찾을 수 있다.
useContext 사용 시 주의할 점
useContext를 함수형 컴포넌트 내부에서 사용할 때는 항상 컴포넌트 재활용이 어려워진다는 점 입니다. (Provider에 의존성을 가지고 있는 셈)
1. 컨텍스트가 미치는 범위를 최대한 좁게 만들어야 한다.
2. useContext는 상태관리 라이브러리가 아니다. 상태를 주입하는 API다. => 단순히 Props 값을 하위로 전달해 준다.
<상태관리 라이브러리>의 조건
어떠한 상태를 기반으로 다른 상태를 만들어 낼 수 있어야 한다.
필요에 따라 이러한 상태 변화를 최적화 할 수 있어야 한다.
3. 부모 컴포넌트가 렌더링되면 하위 컴포넌트는 모두 리렌더링된다
=> React.memo를 사용해야 한다. memo는 props 변화가 없으면 리렌더링되지 않고 계속해서 같은 결과물을 반환할 것이다.
const ChildComponent = memo( () => {
useEffect( () => {
console.log(‘렌더링 ChildComponent’)
})
}
)
Context를 쓰기 전에
- props 전달하기부터 시작하기
- 컴포넌트를 추출하고 JSX를 자식으로 전달하기 => 컴포넌트 사이의 계층 수를 줄일 수 있다.
Context 사용 사례
1. 테마 설정 Theming - 예를 들어 다크모드
2. 현재 계정 Current account
3. 라우팅
4. 상태관리 - 복잡한 상태를 관리하고 번거로움 없이 먼 컴포넌트로 전달하기 위해 리듀서를 함께 사용하는 것도 일반적이다.
결론
useContext로 상태 주입을 최적화했다면 반드시 Provider의 값이 변경될 때 어떤 식으로 렌더링되는지ㅣ 눈여겨보아야 한다. useContext로는 주입된 상태를 사용할 수 있을 뿐, 그 자체로는 렌더링 최적화에 아무런 도움이 되지 않는다.
참조
모던리액트딥다이브
'FrontEnd > React' 카테고리의 다른 글
[ React ] useState vs useReducer (0) | 2024.01.15 |
---|---|
[ React ] useReducer (0) | 2024.01.15 |
[ React ] useRef (0) | 2024.01.14 |
[ React ] imageURL 을 File instance 로 만들기 (0) | 2023.10.26 |
[ React ] Rendering Lists (feat. key ) (0) | 2023.10.24 |