코딩하는라민

[React] Hooks - Context API 본문

Core/React

[React] Hooks - Context API

코딩하는라민 2023. 3. 6. 15:14
728x90
반응형

[React] Hooks - Context API

 

📌 context 를 사용하는 이유

리액트에서는 데이터가 위에서 아래로 props를 통해 전달된다. 즉, 단반향 하향식 데이터 흐름이다.

여러 컴포넌트에 props 을 전해줘야하는 경우 굉장히 번거로워진다.

props 를 하위 컴포넌트에 전달해줄 때 트리 단계마다 명시적으로 props 을 넘겨줘야하는데,

context 를 이용하면 하위 컴포넌트들에 연쇄적으로 props 를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.

 

📌 context 를 언제 사용하는가

  • Header
    • Container
      • Nav

상위 컴포넌트 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 에 전달된 것을 확인할 수 있다.

 

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

📌 context 사용 전 고려할 것

context의 주된 용도는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것이다.

context를 사용하면 컴포넌트를 재사용하기가 어려워지므로 꼭 필요할 때만 써야한다.

그렇다고 context 가 나쁜 것만은 아니다.

여러 레벨에 걸쳐 props 넘기는 걸 대체하는 데에 context보다 컴포넌트 합성이 더 간단한 해결책일 수도 있다.

 

자세한 내용은 공식 문서 확인해보기

 

Context – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

📌 context가 필요 없을 때

 

초보자를 위한 리액트 Context - 완벽 가이드 (2021)

리액트 context는 모든 리액트 개발자들이 필수적으로 알아야 하는 개념입니다. context는 앱에서 state를 쉽게 공유할 수 있게 해줍니다. 이 글에서는 리액트 context가 무엇인지, 어떻게 사용하는지,

www.freecodecamp.org

대부분 여러 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 잘 쓰는 방법

여러분, 리액트로 웹 애플리케이션 개발 하면서 Context API를 어떻게 사용하고 계신가요? 과거에도 관련 포스트를 작성한적이 있긴 하지만, 지난 몇 년간 Context를 사용하면서 습득하게된 팁들을

velog.io

 

 

 

 


참고 : 리액트 공식 문서, 다른 사람들이 안 알려주는 리액트에서 Context API 잘 쓰는 방법 - velog(writted by Minjun Kim)
  등을 공부하고, 간단하게 정리한 내용입니다. 잘못된 부분이나 문제되는 점이 있으면 댓글 부탁드립니다.

728x90
반응형

'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