본문 바로가기
웹개발/리액트

리액트 함수형 컴포넌트에서 context 사용하기

by 어컴띵 2021. 2. 25.

리액트프로그램을 만들다 보면 state만으로는 프로그램에서 사용하는 데이타를 모두 다룰수가 없다. 아니 다룰수는 있겠지만 엄청 번거롭고 복잡해진다.

 

이유는 state는 해당 컴포넌트에서 사용할수도 있지만 다른 컴포넌트에서 state값을 사용하려면 state의 값을 다른 컴포넌트에 사용하기 위해서 최상위 컴포넌트에 state를 정의한다음 state를 사용하고자 하는 컴포넌트에 props로 내려 보내야 한다.

 

하위 컴포넌트가 하나면 큰 문제가 없을수도 있지만 하위의 컴포넌트 갯수가 많아질수록 props로 내려보내야 되는 컴포넌트가 많아지고 state값을 사용하지 않는 컴포넌트도 해당 state를 props로 받아서 state를 사용하는 하위 컴포넌트로 내려보내야 하는 코드를 작성해야한다.

 

이런 불편함을 해결하려면 하나의 전역 저장소가 만들고 그 저장소에 state값을 저장하고, 저장한 state값을 사용하고자하는 컴포넌트에서 해당 state 불러서 사용하면 된다. 

 

여기서는 리액트에서 제공해주는 context를 이용해서 state를 전역으로 사용할수 있게 하는 방법을 알아보기로한다.

참고로 state를 관리해주는 라이브러리 redux와 mobx도 내부적으로는 context를 이용한다고 한다.

 

context는 리액트가 제공해주는 전역저장소로 이해를 하자, 우리는 context에 관리할 state값을 생성하고, 그리고 생성한 state값을 변경할수있게 해주어야한다.

 

상태를 가지는 HelloStateContext를 생성하고, 상태를 변경하는 HelloDispatchContext를 생성한다. 그리고 리듀서 함수를 만들고 Provider컴포넌트에서 useReducer를 사용해서 상태를 받아오고, 상태를 변경하는 메소드를 받아온다. 그리고 hook처럼 사용할수 있게 useHelloState메소드와 useHelloDispatch메소드를 만든다. 소스는 다음과 같다. 

 

먼저 HelloContext.js를 만든다.

import React,{useContext,useState,useReducer} from 'react';

const defaultValue = {
    value:"Hello",
    clickHelloButton: () => {alert()}
};
// 값을 저장할 context를 생성한다.
const HelloStateContext = React.createContext();

// 값을 변경할 함수를 저장할 context를 생성한다.
const HelloDispatchContext = React.createContext();

// 값과 액션을을 파라메타로 받고 액션별로 처리해야할 로직을 만든다.
// 리듀서란 이전상태(state)를 받아서 새로운 상태를 리턴합니다.
// 여기서 state는 이전 상태값이고 action은 상태를 변경시키는 함수이므로
// 기존 state를 가지고 새로운 값을 반환한다.
function helloReducer(state, action){
    switch(action.type){
        case 'clickHello' : {
            const v = state.value=='Hello'?'Hello world':'Hello'
            console.log(state);
            return {value: v}
        }
        default: {
            throw new Error()
        }
    }
}

// Provider를 반환하는 함수를 생성한다.
// children을 Provider로 감싼 컴포넌트이고 childern은 생성한 context를 사용할수 있다.
// useReducer를 이용해서 state(상태값)과, dispatch(상태를변경시키는함수)를 반환받는다.
function HelloProvider({children}){
    const [state, dispatch] = React.useReducer(helloReducer,{value:"Hello"});
    return(
        <HelloStateContext.Provider value={state}>
            <HelloDispatchContext.Provider value={dispatch}>
                {children}
            </HelloDispatchContext.Provider>
        </HelloStateContext.Provider>
    )
}

// state를 가진 context를 반환한다.
function useHelloState(){
    const context = React.useContext(HelloStateContext);
    return context;
}

// state를 변경할 action을 가진 context를 반환한다.
function useHelloDispatch(){
    const context = React.useContext(HelloDispatchContext);
    return context
}

export {
    HelloProvider,
    useHelloState,
    useHelloDispatch,
}


 

그리고 app.js에서 위에서 만든 HelloProvider를 다음과 같이 사용한다.

import Hello from "./Hello";
import HelloButton from "./HelloButton";
import {HelloProvider} from "./HelloContext";
import './App.css';

function App() {
    return (
        <>
            <HelloProvider>
                <Hello />
                <HelloButton/>
            </HelloProvider>
        </>
    );
}

export default App;

 

 

Hello.js

import {useHelloState} from "./HelloContext";

function Hello(){
    const context = useHelloState();
    return(
        <h1>Hello world! {context.value}</h1>
    )
}

export default Hello;

useHelloState메소드를 이용해서 context를 가져오고 context.value로 저장된 context를 표시한다.

 

 

HelloButton.js

import React,{useContext} from 'react';
import {useHelloDispatch, useHelloState} from "./HelloContext";

function HelloButton(){
    const dispatch = useHelloDispatch();
    const state = useHelloState();
    return(
        <button onClick={()=>dispatch({type:"clickHello"})}>{state.value}</button>
    )
}

export default HelloButton;

 

버튼을 클릭하면 dispatch함수에 action.type값을 'clickHello'저장하고 HelloContext에 정의한 helloReducer메소드에서 clickHello로 정의된 로직을 수행한다.

 

다음은 실행한 화면이다.

Hello 버튼을 클릭하면 Hello 뒤에 world가 붙는다.

 

이상 리액스 함수형 컴포넌트에서 context를 사용하는 방법을 알아 보았다.

 

클래스형 컴포넌트는 다음을 참조하자.

참조: ko.reactjs.org/docs/context.html

 

Context – React

A JavaScript library for building user interfaces

ko.reactjs.org

참조: kentcdodds.com/blog/how-to-use-react-context-effectively

 

How to use React Context effectively

How to create and expose React Context providers and consumers

kentcdodds.com