들어가기 전에

사전 요구사항

  • React 기본
  • Hooks

Context API의 이유

  • Context API는 property 들을 매우 자식(손자, 증손자급)에게 전달할때 props 로 전달하는 번거러움을 제거할 수 있습니다.

목표

  • Context API 사용하기 전과 후를 살펴보고 이걸 왜 써야하는지 몸과 마음으로 느끼기

- Context API를 사용하기 전 props를 전달 예시

  • App
    • Header
      • Nav

- 구조는 이렇습니다.

가장 하위인 <Nav> 에서 "Draven"을 출력하는데 이 값은 할아버지격 인 <App>에서 가져옵니다.
하지만 <Nav><Header>하위에 있으므로, <Header> 에도 props를 받아와야 합니다.
즉, 쓸데없는 props={props} 때문에 코드가 아주 지저분 해집니다.

# src/App.js
const App = () => {
  const champion = {
    name: "Draven",
    characteristic: "dirty"
  };

  return (
    <>
      <Header user={champion} />
    </>
  );
};
# src/Header.js
src/Header.js
const Header = ({ user }) => {
  return (
    <>
      <Nav user={user} />
    </>
  );
};
# src/Nav.js
const Nav = ({ user }) => {
  return <>{user.name}</>;
};

결과 = Draven

즉, 손자인 Nav에서 할아버지의 property를 가져오려면 엄마의 props로 가져오는 와야합니다. 근대 만약 97개라면? 네 97대의 자손 모두에게 props를 가져와야 겠죠. 그럼 96번의 user={user}를...

근데 Context API를 통해 props를 여러번 가져오지 않고도 property들을 가져 올 수 있습니다.


문제해결

image.png

inc를 누르면 증가하고 dec를 누르면 감소합니다.
https://codesandbox.io/s/contextapihooks-mumli(결과확인)
컴포넌트 구조는 Context API와 관련 된 것을 제외하고 아래와 같습니다.

  • App
    • Red
      • Blue
        • Green

기존대로 라면 Blue영역과 Green영역에 사용할 함수와 데이터를 props로 넘겨줘야 합니다.

<App>
    <Red>
        <Blue buttonClick={buttonClick}>
            <Green data={data}></Green>
        </Blue>
    </Red>
</App>
<!--물론 코딩은 저렇게 하지않고 각 컴포넌트에서 하위 컴포넌트를 호출 했습니다.
(위 링크에서 확인하시면 좋습니다.)-->
  • 디렉터리 구조

image.png

  • src/context : state를 저장하는 <Provider>컴포넌트를 만들기위해 <Provider>의 상위인 createContext를 만들 파일입니다

  • src/components/ColorProvider : 위에서 만든 createContext를 호출하여 create.Provider를 만들고 state와 setState를 정의합니다

  • src/components/그외 것들 : View 컴포넌트들입니다.

1. createContext만들기

/src/context/Color.context.js

About Color.context.js

  • store의 저장소인 Provider, 즉 <Context.Provider>를 만들기 위해 Context를 만듭니다.

//createContext를 import 해줍니다.
import { createContext } from "react";

//직접 우리가 
const ColorContext = createContext({
//사실 여기 안에있는 데이터는 삭제해도 됩니다.
//왜냐면 ColorContext.Provider에서 state를 관리 할 거라서요.
//하지만 관리할 state가 무엇이 있는지 확인하기 좋습니다.
//그러기에 지우지 않는것을 추천합니다.

//우리가 관리할 state입니다.
  number: 0,
  increase: () => {},
  decrease: () => {}
});

export default ColorContext;

2. Provider만들기

state를 모아둔 것을 Provider(store)라 생각하면 됩니다.

/src/component/ColorProvider.component.js

About "ColorProvider.component.js"

  • export 되는 <ColorProvider>가 하는일

    1. 하위에서 사용 할 statesetState를 정의합니다.
    2. state를 관리할 store를 만들기 위해 creactContext 를 받아와서 ColorContext.Providerreturn 합니다. .
import React, { useState } from "react";
import ColorContext from "../../context/Color.context";

//이 페이지의 특징은 함수같은 것들을 먼저 정의하고 
//useState를 통한 state 및 setState를 나중에 했다는 것입니다.
//여기서 Hook에 관한 이해가 필요합니다.
//생각보다 바로 이해하기 어려우니 심사숙고하며 보는걸 추천합니다.

//사용하고자 하는 컴포넌트 최상위에 지정할 Provider컴포넌트 입니다.  
const ColorProvider = ({ children }) => {

//우리가 Blue에서 사용할 함수입니다.
  const increase = () => {
//그 함수안에서 Hooks의 setNumber()를 사용 했습니다.
//prevState를 받아서 return을 통해 state를 업데이트 합니다.  
    setNumber(prevState => {
      return {
        ...prevState,
        number: prevState.number + 1
      };
    });
  };

  const decrease = () => {
    setNumber(prevState => {
      return {
        ...prevState,
        number: prevState.number - 1
      };
    });
  };

//state초기화 객체 입니다.
  const initialState = {
    number: 0,
    increase,
    decrease
  };
//Hook을 통한 state, setState를 정의합니다.
  const [number, setNumber] = useState(initialState);

  return (  
//ColorProvider에 state를 사용할 컴포넌트들을 호출하려면
//{children}이 있어야 합니다
//그래서 마지막 return에서 {children}을 리턴해줍니다.
    <ColorContext.Provider value={number}>
      {children}
      </ColorContext.Provider>
  );
};

export default ColorProvider;

3. 하위 컴포넌트에서 useContext()를 통해 Provider의 state사용하기.

  1. src/components/App.js
import React from "react";
//state를 사용하기 위해 앞에서 만든 Provider를 가져옵니다.  
import ColorProvider from "./ColorProvider/ColorProvider.component";
import Red from "./Red";
const App = () => {
  return (
//사용하고자 하는 자식들 컴포넌트들 가장 밖에서 <Provider>로 감싸줍니다.
    <ColorProvider>
      <Red />
    </ColorProvider>
  );
};
export default App;
  1. src/components.Red.js
  • return으로 <Blue>컴포넌트를 호출한게 다 입니다.
import React from "react";
import Blue from "./Blue";
import "./App.css";

const Red = () => {
  return (
    <div className="red">
      <Blue>Blue</Blue>
    </div>
  );
};

export default Red;
  1. src/components/Blue.js
  • 여기서 increase와 decrease를 사용하기 위해 가장 상위에서 state의 함수를 가져옵니다.
//저장소를 가져오기위해 useContext를 import합니다.  
import React, { useContext } from "react";
import ColorContext from "../context/Color.context";
import Green from "./Green";
import "./App.css";

const Blue = () => {
//원하는 함수를 useContext(Context)로 불러옵니다.  
  const { increase, decrease } = useContext(ColorContext);
  return (
    <div className="blue">
      //그리고 아래와 같이 사용하면 됩니다.
      <button className="increment" onClick={increase}>
        inc
      </button>
      <button className="decrement" onClick={() => decrease()}>
        dec
      </button>
      <Green>green</Green>
    </div>
  );
};

export default Blue;
  1. src/components/Green.js
//마찬가지로 useContext를 import합니다.  
import React, { useContext } from "react";
import ColorContext from "../context/Color.context";
import "./App.css";
const Green = () => {
//useContext(Context)를 사용하여 사용할 준비를 합니다.  
  const value = useContext(ColorContext);
  return (
    <div className="green">
      //정의했던 state.변수명을 사용해 주면 됩니다.
      <span className="number">{value.number}</span>
    </div>
  );
};
export default Green;

정리

  1. React Context API는 props로 여러차례 전달 해야하는 번거러옴을 줄일수 있습니다.

  2. 그러면 결국 유지보수에 큰 이점이 됩니다.

  3. 그렇다는건 정신건강에 또한 큰 이점이 된다는 것입니다.