Record4me

시작하면 끝을 봐야지

TIL

[TIL] 23_0127 useContext(context API)

잇츄미 2024. 1. 27. 19:21

useContext

-react context의 필요성

부모=> 자식 컴포넌트로 데이터 전달할 때 props로 전달했어.

부모 => 자식 => 그 자식 => 그자식의 자식 => prop driling

 

이런 위에서 아래로 props를 보내는 props drilling

=> 깊이가 너무 깊어지면 부모에서 자식으로 넘겨줄 때 여러개의 컴포넌트있을 경우

어디에서 prop이 왔는 지 알수 없기도하고 오류가 무조건 생기며 원인 파악 힘들어

 

 

props drilling, 출처 : https://ko.react.dev/learn/passing-data-deeply-with-context

 

 

하지만 context API를 쓰면

전역으로 데이터를 관리할 수 있어

어떤 컴포넌트든 전역적으로 선언되어있는 데이터에 접근 가능해.

 

contextAPI 필수 개념

  • createContext : context 생성 (컨텍스트를 만드는)
  • Consumer : context 변화 감지 (컨텍스트의 변화를 감지하는 컨슈머)
  • Provider : context 전달(to 하위 컴포넌트) (컨텍스트를 하위 컨텍스트로 전달할 수 있는)

예시1. GF => Child한테 어떤 정보를 알려줘서 Child가 그 내용을 출력하도록.

-App.jsx

import React from "react";
function App() {
    return <GrandFather />
}

export default App;

 

 

-Child.jsx

import React from "react";

function Child({houseName, pocketMoney}) {
    console.log(houseName)
    console.log(pocketMoney)
    return <div>
    		나는 이 집안의 막내에요!
             <br />
        할아버지가 우리 집 이름은 <span>{houseName}</span>라고 하셨어요.
        <br  />
        게다가 용돈도 <span>{pocketMoney}</span>원 만큼이나 주셨어요!
    </div>
}

export default Child;

 

 

- 결과

 

 

 

Child컴포넌트

import React from "react";

function Child({houseName, pocketMoney}) {
    console.log(houseName)
    console.log(pocketMoney)
    const style={
        color = "red",
        fontWeight: "900"
    }
    
    return <div>
    		나는 이 집안의 막내에요!
             <br />
        할아버지가 우리 집 이름은 <span style={style}>{houseName}</span>라고 하셨어요.
        <br  />
        게다가 용돈도 <span style={style}>{pocketMoney}</span>원 만큼이나 주셨어요!
    </div>
}

export default Child;

 

 

 

-Father.jsx

import React from "react";

function Father({houseName, pocketMoney}) {
    return <Child houseName={houseName} pocketMoney={pocketMoney} />
}

export default Father;

 

 

-GrandFather.jsx

import React from "react";

function GrandFather() {
    const houseName = "라이트하우스";
    const pocketMoney = 10000; // 손자한테 전달
    return <Father houseName={houseName} pocketMoney={pocketMoney}  />
}

export default GrandFather;
  • 이 단계가 100개라면 엄청 비효율 적이야. 그래서 useContext hook을 사용하는거야.

 

 

useContext

- 사용법

import { createContext } from "react";

// provider로 주입하는 하위 컴포넌트에 들어가서 사용할 수 있는
// 컨텍스트가 생성이 된거야 이걸 가져다가 쓸거야.
export const FamilyContext = createContext(null);
  • 용돈을 지급받는 곳이 할아버지 GF 컴포넌트
  • 그래서 GF에서 쓸 거야.

그래서 그냥 Father 컴포넌트에 보내주는 게 아니라 context를 불러와서 감싸줄거야.

그리고 Father에서 보내주는 props는 필요없어.

이제 props로 보내주는 게 아니라

어차피 FamilyContext 만든 걸 통해서 외부로 접근해서 보내줄거야.

그리고 provider를 적용해줄거야. 쩜으로 접근해서 제공하는 자인 provider을 적용할 거야.

 

-GrandFather.jsx

import React from "react";

function GrandFather() {
    const houseName = "라이트하우스";
    const pocketMoney = 10000; // 손자한테 전달
    return (
        <FamilyContext.Provider 
            value={{houseName, pocketMoney}}
            > //context를 provider할 때 보내는 객체
           <Father />
        </FamilyContext.Provider>
        }
}

export default GrandFather;

 

속성(프로퍼티)로 value={}해서 보내는 객체는

{

  houseName: houseName,

  pocketMoney: pocketMoney

}

그리고 javascript에선 키 밸류가 같으면 단축 명명을 할 수 있어서

{ houseName, pocketMoney}로 쓸 수 잇는 거야

그러면 이제 Father 컴포넌트도 프롭스를 받을 필요 엄성

 

 

-Father.jsx

import React from "react";

function Father() {
    return <Child />
}

export default Father;

 

 

이제 Child컴포넌트도 props를 안 받고 props에 의존하지 않고 context를 의존해야해.

그래서 context로 부터 데이터를 받아올 거야.

import React,{ useContext} from "react";

    const style={
        color = "red",
        fontWeight: "900"
    }


function Child({houseName, pocketMoney}) {
 
   const data = useContext(FamilyContext);
    console.log("data", data); // {houseName: "라이트하우스", pocketMoney : 10000}
   const { houseName, pocketMoney} = data;
    
    return <div>
    		나는 이 집안의 막내에요!
             <br />
        할아버지가 우리 집 이름은 <span style={style}>{data.houseName}</span>라고 하셨어요.
        <br  />
        게다가 용돈도 <span style={style}>{data.pocketMoney}</span>원 만큼이나 주셨어요!
    </div>
}

export default Child;

 

-렌더링 문제

useContext를 사용할 때, Provider에서 제공한 value가 달라지면 useContext를 사용하고 있는 모든 컴포넌트가 리렌더링 돼. 그래서 value부분을 항상 신경써줘야 해.

Provider의 value가 달라질 때마다 모든 컴포넌트가 리렌더링 돼.

그 해결책이 "메모이제이션"이야.

 

 

 

 

원래는 이렇게 props로 단계별로 전달받아서 썼지만

이제 FamilyContext로 어느 컴포넌트로 접근할 수 있게 끔한거야.

 

*참고 사이트

- https://ko.react.dev/learn/passing-data-deeply-with-context

 

느낀점

- props만 쓰면 페이지나 기능이 많아지게 되면 props drilling이 심해져서 정말 관리하기 힘들 것 같아. 대신 Context도 provider로 보내는 value가 필요하면 처음으로 찾아가서 설정을 해주고 데이터를 불러서 써야하고 필요한 value값과 페이지가 많아지면 props도 같이 계속 써야하는 건 같은 것 같아. 그래도 props만 전달할 때보단 비교적 편하겠지만..