• [React] Context API와 useReducer로 상태관리하기

    2023. 5. 31.

    by. 지은이: 김지은

    728x90

     

    1. Context API란?

    컴포넌트간에 데이터를 전역적으로 공유하고 전달할 수 있고, 중간 컴포넌트를 거치지 않고도 데이터를 전달 할 수 있다.

     

    2. useReducer란?

    리액트에서 상태관리를 위해 사용되는 훅으로 useReducer를 사용하면 복잡한 상태 로직을 분리하고 관리할 수 있다.

     

    Context API와 useReducer를 함께 사용하면 Context API로 전역 상태를 제공하고 useReducer로 상태를 업데이트 하는 로직을 구현할 수 있어서 상태관리가 편해지고 컴포넌트 간 데이터 전달이 용이해진다.

     

    3. 초기 상태 정의 후 컨텍스트 생성

    import { createContext, useReducer } from "react";
    
    const INITIAL_STATE = {
      city: undefined,
      dates: [],
      options: {
        adult: undefined,
        children: undefined,
        room: undefined,
      },
    };
    
    export const SearchContext = createContext(INITIAL_STATE);
    • INITIAL_STATE로 상태관리를 하기 위한 city, dates, options 등과 같은 속성의 초기값을 정의한다.
    • createContext()함수로 컨텍스트 객체를 생성하는데 인자로 초기값인 INITIAL_STATE 전달하고 컨텍스트 객체 export 하기
    • 컨텍스트 객체 요소: Provider (컨텍스트 값 제공하는 컴포넌트), Consumer (컨텍스트 값 사용하는 컴포넌트)

     

    4. useReducer

    액션은 상태를 업데이트하기 위한 정보를 가지고 있는 객체로 일반적으로 type이라는 필수 프로퍼티를 가지고 있으며 필요에 따라 추가적인데이터를 담을 수 있다.

    const SearchReducer = (state, action) => {
      switch (action.type) {
        case "NEW_SEARCH":
          return action.payload;
        case "RESET_SEARCH":
          return INITIAL_STATE;
        default:
          return state;
      }
    };
    
    export const SearchContextProvider = ({ children }) => {
      const [state, dispatch] = useReducer(SearchReducer, INITIAL_STATE);
    
      return (
        <SearchContext.Provider
          value={{
            city: state.city,
            dates: state.dates,
            options: state.options,
            dispatch,
          }}
        >
          {children}
        </SearchContext.Provider>
      );
    };
    • SearchReducer는 현재 상태와 액션을 받아 다음상태를 반환하는 함수
    • 기본적으로는 현재 상태를 그대로 반환하지만, NEW_SEARCH 액션이 발생하면 action.payload(데이터) 값을 새로운 상태로 설정
    • RESET_SEARCH 액션이 발생하면 INITIAL_STATE 값을 반환하여 상태를 초기화 시켰다.

     

    • useReducer 훅을 사용해서 SearchReducer와 INITIAL_STATE를 기반으로 상태와 액션 디스패치 함수를 생성 (state: 현재 상태를 나타내는 변수, dispatch: 액션을 발생시키는 함수)
    • Provider 컴포넌트는 value 속성을 사용해서 props로 state(city, dates, options)와 dispatch 함수를 하위 컴포넌트에 전달한다.
    • {children}은 SearchContext.Provider 컴포넌트 내부에 있는 하위 컴포넌트들을 랜더링 한다. 이렇게 하면 컨텍스트 값을 사용하는 하위 컴포넌트들에게 컨텍스트를 전달한다.

     

    5.  Provider 컴포넌트에 App 컴포넌트를 감싸기

    <SearchContextProvider>를 최상위에 위치시키는 이유는

    App 컴포넌트와 그 안에 포함된 모든 컴포넌트에서 SearchContext의 값을 사용하고 상태를 업데이트 할 수 있게 하기 위함이다.

     

    <SearchContextProvider>는 SearchContext값을 제공하는 컴포넌트로 이 컴포넌트로 감싸진 하위 컴포넌트들은 SearchContext값을 구독하고 사용할 수 있다.

    // src/index.js
    import { SearchContextProvider } from "./context/SearchContext";
    
    ReactDOM.render(
      <React.StrictMode>
        <SearchContextProvider>
          <App />
        </SearchContextProvider>
      </React.StrictMode>
      document.getElementById("root")
    );

     

    6. 전역 상태 사용하기

    const { dispatch } = useContext(SearchContext);
    
    const handleSearch = () => {
        dispatch({ type: "NEW_SEARCH", payload: { destination, dates, options } });
    };

    useContext를 호출해서 SearchContext값인 state와 dispatch를 가져올 수 있으며 구조 분해 할당으로  dispatch를 추출했다. 이렇게 하면 dispatch 함수를 직접 사용할 수 있다.

     

    이후 handleSearch 함수가 호출 되면 dispatch함수를 호출하여 액션을 발생시키고 액션 객체를 전달한다.

    dispatch함수를 호출해서 위에 정의한 SearchReducer 함수가 동작하고 상태가 업데이트 된다.

     

     

    댓글