본문 바로가기

react

[리액트를 다루는 기술] 15장 Context API

15.1 Context API를 사용한 전역 상태 관리 흐름 이해하기 

 

- Context API는 리액트 프로젝트에서 전역적으로 사용할 데이터가 있을 때 유용한 기능 

 ex) 로그인 정보, 애플리케이션 환경 설정, 테마 etc

 

- 기존에는 최상위 컴포넌트에서 여러 컴포넌트를 거쳐 props로 원하는 상태와 함수를 전달했지만, Context API를 사용하면 Context를 만들어 단 한번에 원하는 값을 받아와서 사용 할 수 있음 

 

15.2 Context  API 사용법 익히기 

 

15.2.1 새 Context 만들기 

 

- 새 Context를 만들 때는 createContext 함수를 사용 

- 파라미터에는 해당 Context의 기본 상태를 지정 

 

Context/color.js

import { createContext } from "react";

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

export default ColorContext;

 

15.2.2 Consumer 사용하기 

 

- ColorBox 컴포넌트를 만들어서 ColorContext 안에 들어 있는 색상을 보여줌 

- ColorContext 안에 들어 있는 Consumer 컴포넌트를 통해 색상 조회 

 

Components/ColorBox.js

import ColorContext from "../Context/color";

const ColorBox = () => {
    return (
        <ColorContext.Consumer>
        {value => (
            <div
            style={{
                width:'64px',
                height:'64px',
                background: value.color
            }}
            />
        )}
        </ColorContext.Consumer>
    )
}

export default ColorBox;

 

- Consumer 사이에 중괄호를 열어서 그 안에 함수를 넣어 줌  => Function as a child (Render Props)

- 컴포넌트의 children이 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달 

 

 

15.2.3 Provider

 

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

- Provider를 사용할 때는 value 값을 명시해 주어야 제대로 작동 

 

App.js

import ColorBox from "./Components/ColorBox";
import ColorContext from "./Context/color";

function App() {
  return (
    <ColorContext.Provider value={{color:'red'}}>
      <div>
        <ColorBox />
      </div>
    </ColorContext.Provider>
  );
}

export default App;

 

15.3 동적 Context 사용하기 

 

15.3.1 Context 파일 수정하기 

 

- Context의 value 값에 함수 전달 가능 

 

Context/color.js

import { createContext, useState } from "react";

const ColorContext = createContext({
    state: {color: 'black', subcolor: 'red'},
    actions: {
        setColor: () => {},
        setSubcolor: () => {}
    }
});

const ColorProvider = ({children}) => {
    const [color, setColor] = useState('black');
    const [subcolor, setSubcolor] = useState('red');

    const value= {
        state: {color, subcolor}, //상태
        action: {setColor, setSubcolor} //업데이트
    };

    return (
        <ColorContext.Provider value={value}>{children}</ColorContext.Provider>
    );
};

//const ColorConsumer = Color.Context.Consumer와 같은 의미 
const {Consumer: ColorConsumer} = ColorContext;

//ColorProvider와 ColorConsumer 내보내기 
export {ColorProvider, ColorConsumer};

export default ColorContext;

 

- ColorProvider 컴포넌트에서는 ColorContext.Provider를 렌더링

- Provider의 value에는 상태는 state로, 업데이트 함수는 actions로 묶어서 전달

 

 

15.3.2 새로워진 Context를 프로젝트에 반영하기 

 

App.js

- ColorContext.Provider를 ColorProvider로 대체 

import ColorBox from "./Components/ColorBox";
import { ColorProvider } from "./Context/color";

function App() {
  return (
   <ColorProvider>
      <div>
        <ColorBox />
      </div>
   </ColorProvider>

  );
}

export default App;

 

components/ColorBox.js

- ColorContext.Consumer를 ColorConsumer로 변경 

import { ColorConsumer } from "../Context/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;

 

 

15.3.3 색상 선택 컴포넌트 만들기 

 

components / SelectColors.js

- Context의 actions에 넣어 준 함수를 호출하는 컴포넌트 

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

const SelectColors =  () => {
    return (
        <div>
            <h2>색상을 선택하세요.</h2>
            <div style={{display:'flex'}}>
                {colors.map(color => (
                    <div
                        key={color}
                        style={{
                            background: color,
                            width:'24px',
                            height:'24px',
                            cursor: 'pointer'
                        }}
                    />
                ))}
            </div>
        </div>
    )
}

export default SelectColors;

 

App.js

import ColorBox from "./Components/ColorBox";
import { ColorProvider } from "./Context/color";
import SelectColors from "./Components/SelectColors";

function App() {
  return (
   <ColorProvider>
      <div>
        <SelectColors />
        <ColorBox />
      </div>
   </ColorProvider>

  );
}

export default App;

 

- 해당 SelectColors에 마우스 왼쪽 버튼을 클릭하면 큰 정사각형의 색상을 변경하고, 마우스 오른쪽 버튼을 클릭하면 작은 정사각형의 색상을 변경하도록 구현

 

components/SelectColors.js

import { ColorConsumer } from "../Context/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;

 

 

15.4 Consumer 대신 Hook 또는 static ContextType 사용하기 

 

- Context에 있는 값을 사용할 때 Consumer 대신 다른 방식을 사용해서 값을 받아오는 방법

 

15.4.1 useContext Hook 사용하기 

 

- 리액트에 내장되어 있는 useContext Hook 사용 

 

components /ColorBox.js

import { useContext } from "react";
import ColorContext from "../Context/color";

const ColorBox = () => {
    const { state } = useContext(ColorContext);

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

export default ColorBox;