일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- JS
- web
- 웹퍼블리셔
- JavaScript
- 웹디실기
- 코드공유
- HTML
- git
- 생활코딩
- 연산자
- 프론트엔드
- 웹디자인기능사
- 렛츠기릿자바스크립트
- react
- jQuery
- github
- 세로메뉴바
- 정보처리기사
- 자바스크립트
- 코딩독학
- PROJECT
- 깃
- 리액트
- 비전공자
- Supabase
- 실기
- 타입스크립트
- 슬라이드전환
- CSS
- 웹디자인기능사실기
- Today
- Total
코딩하는라민
[React] Hooks - Context API 본문
[React] Hooks - Context API
📌 context 를 사용하는 이유
리액트에서는 데이터가 위에서 아래로 props를 통해 전달된다. 즉, 단반향 하향식 데이터 흐름이다.
여러 컴포넌트에 props 을 전해줘야하는 경우 굉장히 번거로워진다.
props 를 하위 컴포넌트에 전달해줄 때 트리 단계마다 명시적으로 props 을 넘겨줘야하는데,
context 를 이용하면 하위 컴포넌트들에 연쇄적으로 props 를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.
📌 context 를 언제 사용하는가
- Header
- Container
- Nav
- Container
상위 컴포넌트 Header 부터 최하위 컴포넌트 Nav 가 있다고 해보자.
Container 에는 props 를 전달하지 않고 Nav 에만 절달하고 싶다.
import React, { useState } from 'react';
function Nav(props) {
return (
<div>
3. Nav : {props.mainColor}
<div mainColor={props.mainColor} />
</div>
);
}
function Container(props) {
return (
<div>
2. Container
<Nav mainColor={props.mainColor} />
</div>
);
}
export default function Header() {
return (
<div>
1. Header
<Container mainColor="purple" />
</div>
);
}
Nav 컴포넌트에 Header 컴포넌트의 props 을 전달하기 위해서 불필요하게 Container 컴포넌트에도 props를 전달했다.
위에서는 하위 컴포넌트들이 2개밖에 되지 않지만, 이게 많아진다면 계속해서 전달하기가 힘들 것이다.
💡 props drilling 💡
props 를 하위 컴포넌트로 전달하는 과정에서 불필요한 props 의 전달이 이루어지는 과정을 말한다.
컴포넌트가 많아지고 이런식으로 props 를 계속해서 전달해주게 되면 마치 드릴로 뚫고 들어가는 것 같기 때문에 이러한 현상을 props drilling 이라고 한다.
Context 를 이용하면 이러한 props drilling 문제를 해결할 수 있다.
하지만 Context 를 사용해도 Context hell 이 발생할 수도 있다.
📌 API
✅ React.createContext
Context 객체를 만든다.
Context 객체를 구독하고 있는 컴포넌트를 렌더링할 때 React는 트리 상위에서 가장 가까이 있는 짝이 맞는 Provider로부터 현재값을 읽는다.
const MyContext = React.createContext(defaultValue);
defaultValue 매개변수는 트리 안에서 적절한 Provider를 찾지 못했을 때만 쓰이는 값이다.
→ 컴포넌트를 독립적으로 테스트할 때 유용
→ Provider를 통해 undefined을 값으로 보낸다고 해도 구독 컴포넌트들이 defaultValue 를 읽지는 않는다.
✅ Context.Provider
Provider 는 Context 에 포함된 React 컴포넌트이다.
이 컴포넌트를 통해서 Context의 값을 정할 수 있다.
Provider 컴포넌트에 value 라는 props 을 설정해준다.
Provider는 context 를 구독하는 컴포넌트들에게 context 의 변화를 알리는 역할을 한다.
즉 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달한다.
Provider 컴포넌틀 감싸면 하위의 컴포넌트에서 Context 값을 조회해서 바로 사용할 수 있게 되는 것이다.
<MyContext.Provider value={/* 어떤 값 */}>
Provider 하위에 또 다른 Provider를 배치하는 것도 가능하다.(제한이 없다.)
이 경우 하위 Provider의 값이 우선시된다.
Provider 의 value prop 이 바뀔 때마다 context 를 구독하는 하위 컴포넌트들은 리렌더링된다!
✅ Context.displayName
Context 객체는 displayName 문자열 속성으로 React 개발자 도구에서 context 를 어떻게 보여줄 지 결정합니다.
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> {/* "MyDisplayName.Provider" in DevTools */}
✅ useContext
useContext 라는 훅을 사용해서 Context 의 내용을 조회할 수 있다.
context 객체(React.createContext에서 반환된 값)를 받아 그 context의 현재 값을 반환한다.
context의 현재 값은 이 Hook을 호출하는 컴포넌트에 가장 가까이에 있는 Provider 컴포넌트의 value prop에 의해 결정된다.
const value = useContext(MyContext);
컴포넌트에서 가장 가까운 Provider 컴포넌트가 갱신되면 이 Hook은 그 MyContext provider에게 전달된 가장 최신의 context value를 사용하여 렌더러를 트리거 합니다.
상위 컴포넌트에서 React.memo 또는 shouldComponentUpdate를 사용하더라도 useContext를 사용하고 있는 컴포넌트 자체에서부터 다시 렌더링됩니다.
📌 context 사용해보기
✅ import
context 를 사용하려면 react 로부터 createContext, useContext 를 import 해야한다.
import { createContext, useContext } from 'react';
✅ createContext
React 에서 제공하는 createContext 함수를 통해 Context 를 생성해서 변수에 넣어준다.
createContext 안에는 디폴드값을 넣어줄 수 있는데 빈 값으로 넘겨줘도 된다.
createContext 로 생성한 데이터는 전역 데이터가 된다.
const mainColorContext = createContext('blue')
✅ Provider
createContext 로 생성한 변수에 Provider 를 최상위 컴포넌트에 return 태그들을 Provider 로 감싸준다.
Privider 전달자는 하위 컴포넌트에서 전역 데이터에 접근할 수 있게 해준다.
export default function Header() {
return (
<mainColorContext.Provider value="purple">
1. Header
<Container />
</mainColorContext.Provider>
);
}
예전에는 consumer 를 이용했으나, 현재는 사용하지 않는다.
Provider 를 사용하자!
✅ useContext
useContext 를 이용해 createContext 로 생성해준 변수(mainColorContext)를 인자로 받아 변수(myContext)에 저장해준다.
const myContext = useContext(mainColorContext);
적용해주고자 하는 컴포넌트에 prop 에 해당 값을 넣고, 제대로 prop 이 전달되었는지 확인해보자.
function Nav() {
const myContext = useContext(mainColorContext);
return (
<div>
3. Nav : {myContext}
<div mainColor={myContext} />
</div>
);
}
이렇게 Header 의 prop 이 Nav 에 전달된 것을 확인할 수 있다.
📌 context 사용 전 고려할 것
context의 주된 용도는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것이다.
context를 사용하면 컴포넌트를 재사용하기가 어려워지므로 꼭 필요할 때만 써야한다.
그렇다고 context 가 나쁜 것만은 아니다.
여러 레벨에 걸쳐 props 넘기는 걸 대체하는 데에 context보다 컴포넌트 합성이 더 간단한 해결책일 수도 있다.
자세한 내용은 공식 문서 확인해보기
📌 context가 필요 없을 때
대부분 여러 depth 의 컴포넌트에 props 를 내려줘야하는 경우 Context 를 많이 사용한다.
props drilling 의 이유로 Context 에 의지하게 된다.
하지만
Context 를 사용하는 것 보다도 상위 컴포넌트에 바로 하위 컴포넌트를 넣어준다면, 굳이 Context 를 사용하지 않고도, props drilling 를 걱정하지 않아도 된다.
따라서 Context 를 사용하지 않고도 구조 개선을 통해서 문제를 해결할 수도 있다.
- props drilling 되고 있는 토글 버튼 코드(연습)
function Nav(props) {
return (
<>
<p>Nav</p>
<button value={props.value} onClick={props.onClick}>
{props.value ? '리액트' : '타입스크립트'}
</button>
</>
);
}
function Container(props) {
return (
<div>
<p>Container</p>
<Nav value={props.value} onClick={props.onClick} />
</div>
);
}
export default function Header() {
const [state, setState] = useState(true);
const handler = () => {
setState(!state);
};
return (
<div>
<p>Header</p>
<Container value={state} onClick={handler} />
</div>
);
}
- 개선된 토글 버튼 코드(연습)
function Container({Nav}) {
return (
<div>
<p>Container</p>
{Nav}
</div>
);
}
export default function Header() {
const [state, setState] = useState(true);
const handler = () => {
setState(!state);
};
const Nav = (
<>
<p>Nav</p>
<button onClick={handler}>{state ? '리액트' : '타입스크립트'}</button>
</>
)
return (
<div>
<p>Header</p>
<Container value={state} onClick={handler} Nav={Nav} />
</div>
);
}
📌 context로 상태관리하기
참고 : 리액트 공식 문서, 다른 사람들이 안 알려주는 리액트에서 Context API 잘 쓰는 방법 - velog(writted by Minjun Kim)
등을 공부하고, 간단하게 정리한 내용입니다. 잘못된 부분이나 문제되는 점이 있으면 댓글 부탁드립니다.
'Core > React' 카테고리의 다른 글
[React] React Router (1) | 2023.03.13 |
---|---|
[React] Hooks - useMemo (최적화하기) (0) | 2023.03.06 |
[React] Hooks - useEffect ( ) (0) | 2023.03.05 |
[React] 라이프사이클(LifeCycle) - React 의 생명주기 (1) | 2023.03.05 |
[React] Hooks - useState ( ) (0) | 2023.03.05 |