ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React.js] Hooks - useContext (Context API)
    Front-End(Web)/React - 프레임워크(React, Next) 2020. 12. 25. 20:33
    반응형

    React 미니 프로젝트들을 수행하다보니, useContext, useReducer 사용을 하라는 미션이 주어졌다. 이 개념에 대한 선행학습을 해봤다.


    📒 React Context

    useContext 훅을 공부하기 전에, React의 Context 개념에 대해 우선 이해를 할 필요가 있다.

     

    1. Context 개념

    React App은 많은 컴포넌트들로 구성되어있고, 어떤 정보(props 값이나 함수)는 여러 컴포넌트를 거쳐 전달되는 경우가 존재한다.

    이러한 정보들을 전역적으로 사용하기 위해 Context에서 이를 관리 및 공유해주며, 이를 사용하기 위한 기능을 Context API라 한다.

     

    - 언제 Context를 써야 할까?

    전역적(global) 데이터 공유에 특화된 방법으로, 로그인 유저 데이터, 설정파일, 테마, 언어 등이 해당된다.

     

    - Context 사용전에 고려할 것

    context를 사용하면 컴포넌트 재사용이 어려워지므로, 꼭 필요한 경우에만 사용하는 것이 좋다.

    많은 컴포넌트들로 구성되있어도, 정보가 한 곳에서만 사용된다면 컴포넌트 병합을, 여러 곳에서 사용된다면 Context가 유리한 것이다. 

     

    2. Context API

    Context 기능을 편리하게 사용할 수 있게 해주는 API들이다. (Redux, React Router, Styled Component 등 라이브러리의 기반기술)

     

    1) React.createContext

    const MyStore = React.createContext(default);
    • 새 Context 객체를 만든다. 이 Context를 사용하려는 컴포넌트 상위에, 부모(Provider) 및 value 설정을 통해 이 값을 하달한다.
    • default는 트리 안에서 적절한 Provider를 찾지 못했을 때 쓰이는 값.  

    2) Context.Provider

    <MyStore.Provider value={this.state}>
      <targetComponent1 />
      <targetComponent2 />
    </MyStore.Provider>
    • 정의한 Context를 하위 컴포넌트에 전달하는 역할. Provider 변수는 꼭 value = {} 를 사용해야 한다.
    • Provider value로 가진 state가 변할 때마다, 해당 Context들은 전부 Re-rendering 된다.
    • 전달받는 하위 컴포넌트의 갯수에는 제한이 없다.
    • Provider에 하위 Provider 배치도 가능하며, 이 때 하위 Provider 값이 우선시된다.

    3) Context.Consumer

    <MyContext.Consumer>
      {value => value.message}
    </MyContext.Consumer>
    • Context 변화를 추적하는 컴포넌트이다. 
    • Context를 통해 렌더링하는 함수(컴포넌트)를 자식값으로 가진다. Consumer의 참고값은, 가장 가까운 Provider 이다.
    • 상위 Provider가 없다면, createContext() 시 default 값을 반영한다.
    // color.js
    import { createContext } from "react";
    
    const ColorContext = createContext({ color: "black" });
    export default ColorContext;
    
    
    // ColorBox.js
    import React from "react";
    import ColorContext from "../contexts/color";
    
    const ColorBox = () => {
      return (
        <ColorContext.Consumer>
          {(value) => (
            <div
              style={{ width: "64px", height: "64px", background: value.color }}
            />
          )}
        </ColorContext.Consumer>
      );
    };
    
    export default ColorBox;
    
    
    // App.js
    import React from "react";
    import "./styles.css";
    import ColorBox from "./components/ColorBox";
    import ColorContext from "./contexts/color";
    
    export default function App() {
      return (
        <ColorContext.Provider value={{ color: "red" }}>
          <div className="App">
            <ColorBox />
          </div>
        </ColorContext.Provider>
      );
    }

    위 예시처럼, createContext, Provider 설정부터 Consumer 콜백함수 작성까지 Context 활용하는 과정이 매우 복잡하다. 

    Consumer 컴포넌트 작성을 보다 편하고 직관적으로 작성해주도록 하는 Hooks가 바로 useContext 인 것이다.


    📒 useContext

    위 설명처럼, Consumer 과정을 직관화하면서 Context 활용을 보다 쉽게 해주는 Hooks 이다.

    인용한다면, 한때는 Context 사용을 지양하라는 공식문서의 언급이 있을 정도였지만, 이 Hooks가 지원되면서 Redux를 대체하는 추세이다.

     

    - 사용법

    1) createContext 생성 : Context API 와 동일

    // context.js
    import React, { createContext } from "react";
    
    export const AppContext = createContext();

     

    2) Provider 생성, context 함수 및 데이터 저장

    // App.js
    const App = () => {
      const [text, setText] = useState("test");
    
      const logText = text => {
        console.log("test");
      };
      return (
        <AppContext.Provider
          value=
        >
          <ViewLayout />
        </AppContext.Provider>
      );
    };
    export default App;

    ViewLayout 이라는 자식 컴포넌트에 Context를 하달하는 App 컴포넌트이다.

     

    3) 자식 컴포넌트 context 호출 : useContext

    // viewlayout.js
    
    import React, { useContext } from "react";
    import { AppContext } from "./App";		// App에 선언 된 context 호출
    
    const ViewLayout = () => {
      const { text, setText, logText } = useContext(AppContext);
    
      return (
        <div>
          <div>{text}</div>
          <button onClick={() => setText("changeText")}>text 변경</button>
          <button onClick={() => logText("log")}>console.log 출력</button>
        </div>
      );
    };
    export default ViewLayout;

    부모 컴포넌트(Provider)의 AppContext Context를 가져오고, 설정된 값들을 useContext Hooks를 통해 위처럼 불러온다.

    Consumer 과정이 간소해진 것을 확인할 수 있다.

     


    📒 Redux vs Context API

    - Redux 란?

    Redux 역시 전역상태를 생성 및 관리하는 라이브러리이다. React 뿐만 아니라, Vue, Angular 도 사용가능한 장점이 있다.

    • Store : 전역상태를 저장(객체형태). Reducer를 통하지 않으면 접근할 수 없다. 하나의 앱엔 하나의 Store만 존재
    • Reducer : Store에 유일하게 접근할 수 있는 객체. Action에 따라 행동하며, Reducer 반환값은 Store에 갱신
    • Action : Reducer에 행동할 동작을 지시(트리거)
    • Subscription : Store에 보관된 전역상태를 반환

    - Redux와 Context API 차이점

    전역상태 관리라는 목적에서, 둘의 차이는 거의 없다. 위에서 언급했듯, Redux는 Context API 기반의 라이브러리이다.

    전역상태 관리 외 제공되는 기능 목적에서 Redux가 사용된다.

    • 로컬 스토리지 상태를 영속적으로 저장하고 불러오는 데 뛰어난 성능을 보임
    • 상태를 서버에 미리 채운 뒤, HTML에 담아 클라이언트로 보내고 앱을 시작할 때 다시 불러오는 동작이 뛰어남
    • 사용자의 액션을 직렬화해서 버그 리포트에 첨부(개발자들은 이를 통해 에러를 재현가능)
    • 이외에도, 액션객체 관리, 실행취소 내역 관리, 현재상태 선계산 등의 장점들이 있다.

    useContext 훅에 대해 공부하려고 했는데, React의 Context 개념에 대해서도 알아야됬고, 나아가 Redux까지 건드렸다.

    뜻하지 않게 포스팅이 길어졌지만, 그만큼 유의미한 성과다.

     

    redux는 지나가면서 종종 들었지만 검색을 미루고 미뤄왔는데, 이렇게 우연치 않게 알게 되어 흐뭇하다.

    Context의 경우엔, 동적 Context 등 더 많은 개념들이 있지만 미니 프로젝트를 진행하는데 있어 기본적인 개념정리를 위한 포스팅으로 우선 마무리하겠다.

     

    <출처>
    kyounghwan01 님의 github 블로그 : https://kyounghwan01.github.io/blog/React/react-context-api/
    Minhyeong Jang 님의 github 블로그 : https://minhyeong-jang.github.io/doriri/2019/12/11/context-hooks
    cada.log 님의 블로그 : https://velog.io/@cada/React-Redux-vs-Context-API

     

    반응형
Designed by Tistory.