image


Q. Redux가 무엇이라고 생각하시나요?

  • redux는 하향식 props 전달을 하게 될 경우 생기는 비효율성을 해결하기 위해 만들어진 중앙 상태 관리 라이브러리라고 생각합니다.
  • redux를 사용하지 않으면 어떤 비효율성이 있을까?
    • 상위 컴포넌트가 하위 컴포넌트에게 props를 전달하게 될 경우 중간 컴포넌트는 해당 props가 필요하지 않는데 상위 컴포넌트에게 받아서 하위 컴포넌트에게 넘겨줘야 하는 상황이 발생합니다.
    • 개발자가 props의 흐름을 다 알고 있어야 합니다. 동료 개발자는 props의 흐름에 대해서 알지 못하게 됩니다.
    • 여러 컴포넌트에서 공유하는 State를 사용하기 위해 상위 컴포넌트에서 여러 컴포넌트로 props를 전달하는 불필요한 반복이 나타나게 됩니다.

1. redux를 사용하지 않은 경우

1570705677526

2. redux를 사용한 경우

  • 여러 컴포넌트에서 하나의 State를 사용할 경우 Redux의 Store를 가르키기만 하면 됩니다.

  • 상위 컴포넌트가 데이터 처리 요청 후 Redux의 Store에 State를 Set해놓으면 해당 State를 사용하는 컴포넌트는 모두 Render됩니다.

    1570706849167


Q. Redux를 어떻게 사용했나요?

  • 크게 보면 페이지 별로 Reducer를 만들고 rootReducer에서 모든 Reducer들을 컴바인 해서 하나의 rootReducer로 사용했습니다.

  • 각각의 Reducer 파일 구조는 아래와같이 Types, Actions, Reducer 이 세개의 파일로 작성했습니다.

    • reducer/auth/authTypes.tsx

      // action의 type의 type
      export const TOGGLE_SIGNUP_POPUP = "TOGGLE_SIGNUP_POPUP";
      export const TOGGLE_SIGNIN_POPUP = "TOGGLE_SIGNIN_POPUP";
      export const LOGIN = "LOGIN";
      export const LOGOUT = "LOGOUT";
          
      // authReducer의 initialState type
      export interface IAuthState {
        isSignUpPopUpShow: boolean;
        isSignInPopUpShow: boolean;
        loggedInUser: user;
      }
          
      // actionCreator 의 type
      interface showSignUpPopUpAction {
        type: typeof TOGGLE_SIGNUP_POPUP;
        isSignUpPopUpShow: boolean;
      }
          
      interface showSignUpPopInAction {
        type: typeof TOGGLE_SIGNIN_POPUP;
        isSignInPopUpShow: boolean;
      }
          
      export interface user {
        id: string;
        seq: number;
        type: string;
      }
          
      interface logInAction {
        type: typeof LOGIN;
        user: user;
      }
          
      interface logOutAction {
        type: typeof LOGOUT;
      }
          
      export type AuthActionType =
        | showSignUpPopUpAction
        | showSignUpPopInAction
        | logOutAction
        | logInAction;
          
      
      • 로그인, 회원가입 화면을 보여주거나 숨기는 액션의 이름, Type 정의

      • AuthReducer에서 사용될 State의 Type 정의

      • Action은 각각 export type 하는 것이 아니라 하나의 AuthActionType이라는 Type으로 사용했습니다.

        export type AuthActionType =
          | showSignUpPopUpAction
          | showSignUpPopInAction
          | logOutAction
          | logInAction;
        
    • reducer/auth/authActions.tsx

      import {
        AuthActionType,
        TOGGLE_SIGNUP_POPUP,
        TOGGLE_SIGNIN_POPUP,
        LOGIN,
        LOGOUT,
        user
      } from "./authTypes";
          
      // actionCreator 정의
      export const toggleSignUpPopUp = (
        isSignUpPopUpShow: boolean
      ): AuthActionType => {
        return {
          type: TOGGLE_SIGNUP_POPUP,
          isSignUpPopUpShow
        };
      };
          
      export const toggleSignInPopUp = (
        isSignInPopUpShow: boolean
      ): AuthActionType => {
        return {
          type: TOGGLE_SIGNIN_POPUP,
          isSignInPopUpShow
        };
      };
          
      export const logInAction = (user: user) => {
        return {
          type: LOGIN,
          user
        };
      };
          
      export const logOutAction = () => {
        return {
          type: LOGOUT
        };
      };
          
      
      • Actions.tsx파일에서는 Action을 return 해주는 ActionCreator를 정의하는 곳입니다.
    • reducer/auth/authReducer.tsx

      import {
        IAuthState,
        AuthActionType,
        TOGGLE_SIGNUP_POPUP,
        TOGGLE_SIGNIN_POPUP,
        LOGIN,
        LOGOUT
      } from "./authTypes";
          
      const initialState: IAuthState = {
        isSignUpPopUpShow: false,
        isSignInPopUpShow: false,
        loggedInUser: JSON.parse(sessionStorage.getItem("LoggedInUser"))
      };
          
      const authReducer = (
        state = initialState,
        action: AuthActionType
      ): IAuthState => {
        switch (action.type) {
          case TOGGLE_SIGNUP_POPUP:
            return {
              ...state,
              isSignUpPopUpShow: !state.isSignUpPopUpShow
            };
          case TOGGLE_SIGNIN_POPUP:
            return {
              ...state,
              isSignInPopUpShow: !state.isSignInPopUpShow
            };
          case LOGIN:
            sessionStorage.setItem("LoggedInUser", JSON.stringify(action.user));
            return {
              ...state,
              loggedInUser: action.user
            };
          case LOGOUT:
            sessionStorage.removeItem("LoggedInUser");
            return {
              ...state,
              loggedInUser: null
            };
          default:
            return state;
        }
      };
          
      export default authReducer;
          
      
      • Reducer.tsx파일에서는 Reducer에 사용될 초기 State인 initialState를 정의했고, Dispatch에 의한 Action이 들어왔을 때 어떤 동작을 할 것인지 정의하는 Reducer를 만들었습니다.
    • reducer/index.tsx

      import HeaderReducer from "./header/headerReducer";
      import SearchPageReducer from "./searchPage/searchPageReducer";
      import AuthReducer from "./auth/authReducer";
      import MyPageReducer from "./myPage/myPageReducer";
      import { IMyPageState } from "./myPage/myPageTypes";
      import { combineReducers } from "redux";
      import { IHeaderState } from "./header/headerTypes";
      import { ISearchPageState } from "./searchPage/searchPageTypes";
      import { IAuthState } from "./auth/authTypes";
      export interface rootState {
        HeaderReducer: IHeaderState;
        SearchPageReducer: ISearchPageState;
        AuthReducer: IAuthState;
        MyPageReducer: IMyPageState;
      }
          
      const rootReducer = combineReducers({
        HeaderReducer,
        SearchPageReducer,
        AuthReducer,
        MyPageReducer
      });
      export default rootReducer;
          
      
      • index.tsx에서는 프로젝트에 사용하는 모든 Reducer를 import 해서 redux의 combineReducers를 사용해 rootReducer로 묶어줍니다.
      • rootReducer도 type을 정해줘야 하는데 rootReducer에 사용되는 모든 reducer의 initialState를 사용하면 됩니다.

Q. Redux를 사용하며 느낀 점.

  • 기존에 일일히 하위 컴포넌트로 props를 넘겨주는 방식은 데이터가 많아질 경우 데이터의 흐름을 파악하기 어려웠던 경향이 있었습니다.
  • Redux를 사용하게 될 경우, 백엔드에서 요청한 데이터를 Redux의 Store에 넣어주기만 하면 해당 State를 사용하는 모든 컴포넌트가 자동으로 Render되기 때문에 데이터를 Store에 넣어주는 로직만 생각하면 돼서 편했습니다.

  • redux를 사용해보기 전에 Context를 사용해서 상태관리를 했었습니다. Context를 사용했을 때보다 action, type, reducer와 같은 어려운 개념이 나와서 개념을 익히는데 좀 어려웠습니다.
  • TypeScript와 함께 사용하다보니 action의 type, state의 type까지도 다 정해줘야 해서 번거로웠지만, 익숙해지니 편했습니다.
  • Redux를 TypeScript, ReactHooks와사용한 이슈에 대해서는 TypeScript + Redux + ReactHooks = ???에서 자세히 확인하실 수 있습니다.