옝옹
냠
옝옹
전체 방문자
오늘
어제
  • 분류 전체보기 (84)
    • [LG유플러스]유레카 SW (5)
    • React (20)
    • JS (17)
    • TypeScript (5)
    • CSS & HTML (1)
    • 알고리즘 (11)
    • JAVA (20)
    • GIT (1)
    • 자격증 (4)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • js
  • useMemo
  • 기본api클래스
  • switch문
  • java
  • 타입스크립트
  • 백준
  • 노마드코더
  • 타입변환
  • 접근제한자
  • 인스턴스멤버
  • 자바
  • map() 함수
  • 혼자공부하는자바
  • do-while문
  • java.lang패키지
  • 리액트
  • Node.js
  • reverse() 메서드
  • 자바스트립트
  • 템플릿리터럴
  • java.util패키지
  • continue문
  • map
  • useEffect
  • sort() 메서드
  • TypeScript
  • JavaScript
  • 리액트를다루는기술
  • 함수선언
  • ==
  • template literal
  • useState
  • toFixed
  • 변수선언
  • 화살표함수
  • 정적멤버
  • join()
  • reduce
  • indexOf()
  • While문
  • fillter
  • useCallback
  • 혼자 공부하는 자바
  • join() 메서드
  • useRef
  • match()
  • 자바스크립트
  • 코드스플리팅
  • break문

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
옝옹

냠

[React] Context API
React

[React] Context API

2023. 4. 5. 02:59

Context

  • Context는 리액트 컴포넌트간에 어떠한 값을 공유할 수 있게 해주는 기능
  • Context API는 Redux나 Mobx 같은 상태관리 라이브러리들의 기반이 됨
  • 전역적으로 사용할 데이터가 있을 때 유용한 기술
    • 예를 들면 사용자 로그인 정보, 애플리케이션 환경 설정, 테마 등
  • 주로 Context는 전역적(global)으로 필요한 값을 다룰 때 사용하는데 꼭 전역적일 필요는 없음

→ 단순히 "리액트 컴포넌트에서 Props가 아닌 또 다른 방식으로 컴포넌트 간에 값을 전달하는 방법이다" 라고 접근을 하는 것이 좋음

컴포넌트에게 데이터를 전달할 때 Props로만 데이터를 전달하게 되면 깊숙히 위치한 컴포넌트에 데이터를 전달해야 하는 경우, 여러 컴포넌트를 거쳐 연달아 Props를 설정해주어야 하기 때문에 불편하고 실수할 가능성이 높아짐(그림 15-2)

→ 이러한 문제들을 Context API를 사용해 Context를 만들어 단 한번에 원하는 값을 받아와 해결


Context API 사용법

// contexts/color.js
import { createContext } from 'react';

const ColorContext = createContext({ color : 'black' });

export default ColorContext;
  • Context 는 리액트 패키지에서 createContext 라는 함수를 사용
  • 파라미터에는 해당 Context의 기본 상태를 지정함
// components/ColorBox.js
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;
  • ColorBox라는 컴포넌트를 만들어 ColorContext 안에 들어있는 색상을 보여줌
  • 색상을 props로 받아오는 것이 아니라 ColorContext 안에 들어 있는 Consumer라는 컴포넌트를 통해 색상을 조회
  • Consumer 사이에 중괄호를 넣어 그 안에 함수를 넣어줌
    • Function as a child, 혹은 Render Props라고 한다
    • 컴포넌트의 children이 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달하는 것
더보기

Render Props 패턴

const RenderPropsSample = ({ children }) => {
	return <div>결과 : {children(5)}</div>;
};

export default RenderPropsSample;

위와 같은 컴포넌트가 있다면 추후 사용할 때 다음과 같이 사용

<RenderPropsSample>{value => 2 * value}</RenderPropsSample>;

RenderPropsSample에게 children props로 파라미터에 2를 곱해서 반환하는 함수를 전달하면 해당 컴포넌트에서는 이 함수를 5에 인자로 넣어서 "결과 : 10"을 렌더링함

// App.js
import ColorBox from './components/ColorBox';
const App = () => {
	return (
    	<div>
        	<ColorBox />
        </div>
    );
};
export default App;

Provider를 사용하면 Context의 value를 변경할 수 있음

// App.js
import ColorBox from './components/ColorBox';
import ColorContext from './contexts/color';
const App = () => {
	return (
    	<ColorContext.Provider value = {{ color : "red" }}>
            <div>
                <ColorBox />
            </div>
        </ColorContext.Provider>
    );
};
export default App;

기존에 createContext 함수를 사용할 때는 파라미터로 Context의 기본값을 넣어주는 것은 Provider를 사용하지 않았을 때만 사용된다. 만약 Provider는 사용했는데 value를 명시하지 않았따면, 이 기본값을 사용하지 않기 때문에 오류가 발생


동적 Context

  • Context의 value에는 함수를 전달해 줄 수 도 있음
  • Context 값을 업데이트 하는 경우 사용
    • Provider 사용시 초기값 변경은 가능하나 클릭 이벤트나 값을 변경하는 이벤트는 불가능함
// contexts/color.js

// - Context와 Provider 컴포넌트로 구성됨
import { createContext, useState } from 'react';

// - createContext의 기본값은 실제 Provider의 value에 넣는 객체의 형태와 일치시키는게 좋음
const ColorContext = createContext({
	state : { color : 'black', subcolor : 'red' },
    actions : {
    	setColor : () => {},
        setSubcolor : () => {}
    }
});

const ColorProvider = ({ children }) => {
	const [color, setColor] = useState('black');
    const [subcolor, setSubcolor] = useState ('red');
    
    // Provider의 상태는 state로 업데이트 함수는 actions로 묶어서 전달
    // Context에서 값을 동적으로 사용할 때 반드시 묶어줄 필요는 없지만, 
    // state와 actions 객체를 따로 분리해주면 다른 컴포넌트에서 Context의 값을 사용할 때 편리
    const value = {
    	state : {color, subcolor},
        actions : {setColor, setSubcolor}
    };
    return (
    	<!-- ColorContext.Provider를 렌더링 
        -->
    	<ColorContext.Provider value = {value}> {children} </ColorContext.Provider>
    );
};

<!-- const ColorConsumer = ColorContext.Consumer와 같은 의미 -->
const { Consumer : ColorConsumer } = ColorContext;

<!-- ColorProvider와 ColorConsumer 내보내기 -->
export { ColorProvider, ColorConsumer };
        
export default ColorContext;

→ 요약해보자면 Update 함수를 Context로 넘겼다

// App.js

// App 컴포넌트에서 ColorContext.Provider를 ColorProvider로 대체함
import ColorBox from './components/ColorBox';
import { ColorProvider } from './contexts/color';

const App = () => {
	return (
    	<ColorProvider>
        	<div>
            	< ColorBox />
            </div>
        </ColorProvider>
    );
};

export default App;
// components/ColorBox.js

// ColorContext.Consumer를 ColorConsumer로 변경하세요
import React from "react";
import { ColorConsumer } from "../contexts/color";

const ColorBox = () => {
  return (
    <ColorConsumer>
      {(value) => (
        <>
          <div
            style={{
              width: "64px",
              height: "64px",
              background: value.state.color,
            }}
          />

          <div
            style={{
              width: "32px",
              height: "32px",
              background: value.state.subcolor,
            }}
          />
        </>
      )}
    </ColorConsumer>
  );
};

export default ColorBox;

value 조회하는 것을 생략할 수 있음

  {({ state }) => (
        <>
          <div
            style={{
              width: "64px",
              height: "64px",
              background: state.color,
            }}
          />

          <div
            style={{
              width: "32px",
              height: "32px",
              background: state.subcolor,
            }}
          />
        </>
      )}

 

// components/SelectColor.js
import React from "react";
import { ColorConsumer } from "../contexts/color";

const colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];

const SelectColors = () => {
  return (
    <div>
      <h2>색상을 입력하세요.</h2>
      <ColorConsumer>
        {({ actions }) => (
          <div style={{ display: "flex" }}>
            {colors.map((color) => (
              <div
                key={color}
                style={{
                  background: color,
                  width: "24px",
                  height: "24px",
                  cursor: "pointer",
                }}
                onClick={() => actions.setColor(color)}
                onContextMenu={(e) => {
                  e.preventDefault();
                  <!-- 마우스 오른쪽 버튼 클릭 시 메뉴가 뜨는 것을 무시 -->
                  actions.setSubcolor(color);
                }}
              />
            ))}
          </div>
        )}
      </ColorConsumer>
      <hr />
    </div>
  );
};

export default SelectColors;
// App.js

import React from "react";
import ColorBox from "./components/ColorBox";
import SelectColors from "./components/SelectColors";
import { ColorProvider } from "./contexts/color";

const App = () => {
  return (
    <ColorProvider>
      <div>
        <SelectColors />
        <ColorBox />
      </div>
    </ColorProvider>
  );
};

export default App;


useContext Hook 사용

  • useContext Hook은 함수형 컴포넌트에서만 사용가능

static contextType 사용

  • 클래스형 컴포넌트에서 Context를 좀 더 쉽게 사용하기 위해 static context Type을 정의
  • 기존 selectColors의 컴포넌트를 클래스형으로 변경
  • useContext를 사용하는게 더 권장
저작자표시 비영리 변경금지 (새창열림)

'React' 카테고리의 다른 글

[React] 리덕스를 사용해 상태 관리  (0) 2023.04.06
[React] 리덕스 라이브러리  (0) 2023.04.05
[React] 라우팅  (0) 2023.03.30
[React] immer를 사용해 불변성 유지  (0) 2023.03.29
[React] 컴포넌트 스타일링  (1) 2023.03.23
    'React' 카테고리의 다른 글
    • [React] 리덕스를 사용해 상태 관리
    • [React] 리덕스 라이브러리
    • [React] 라우팅
    • [React] immer를 사용해 불변성 유지
    옝옹
    옝옹

    티스토리툴바