ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [타자치자 #2] 리팩토링(Redux)
    Project 2021. 3. 10. 12:27
    프로젝트
    1. 타자치자(1.0.1) - 한글타자연습

    2. 리팩토링(Redux)
    3. 리팩토링(TypeScript)
    4. 타자치자(1.0.2) - 기능 추가
    5. 타자치자(1.0.3) - 모바일
    6. 타자치자(1.0.4) - 모바일 장치에서 타수 결과가 Infinity
    7. 리팩토링(redux, styled-components)

     

    타자치자 놀러가기

     

    1. 상태 관리의 필요성

    리덕스를 사용하면 상태 값을, 컴포넌트에 종속시키지 않고, 상태 관리를 컴포넌트의 바깥에서 관리할 수 있게 된다. 사실 타자치자 프로젝트는 규모가 복잡하지 않고, 구조가 간단하여 글로벌 상태 관리가 따로 필요 없지만 편리함을 경험해보고 추후에 익숙하게 사용하기 위해 redux를 적용해 리팩토링 하였다. 먼저 상단 메뉴 버튼(햄버거)에 적용해봤고, 그 이후에 타자 측정, 랭킹 페이지까지 적용하였다.

     

    2. Redux 동작 방식

    - Store : 프로젝트당 1개만 등록, 상태와 리듀서를 관리

    - Action : 프로젝트에 상태변화를 일으키는 것을 액션이라고 한다. 

    - Action Creator : 액션을 만드는 함수이다. 

    - Dispatch : 액션을 발생시키는 것이다. action을 매개변수로 받아 reducer를 호출한다.

    - Reducer : 리듀서는 현재의 상태와 전달받은 액션을 참고하여 새로운 상태를 반환한다.

     

    3. Redux 적용

    npm i redux react-redux

    react-redux는 redux를 컴포넌트 상에서 더 간편하게 사용할 수 있게 해 주는 라이브러리

     

    4. Nav

    4-1. actions

     

    src/action/nav.js

    // Action type
    export const OPEN_NAV = "nav/OPEN_NAV";
    export const CLOSE_NAV = "nav/CLOSE_NAV";
    
    // Action creator
    export const openNav = () => {
      return {
        type: OPEN_NAV,
      };
    };
    
    export const closeNav = () => {
      return {
        type: CLOSE_NAV,
      };
    };

    Action type를 정의하고 그에 맞는 Action Creator를 만든다.

     

    4-2. reducers

    src/reducers/index.js

    import { combineReducers } from "redux";
    
    import nav from "./nav";
    
    const rootReducer = combineReducers({
      nav,
    });
    
    export default rootReducer;

    index.js를 통하여 여러 reducer를 combineReducers로 묶어 줄 수 있다.

     

    src/reducers/nav.js

    import * as navActions from "../actions/nav";
    
    const initialState = {
      isOpen: 0,
    };
    
    const reducers = (state = initialState, action) => {
      const { type } = action;
      switch (type) {
        case navActions.OPEN_NAV: {
          return {
            ...state,
            isOpen: state.isOpen + 1,
          };
        }
        case navActions.CLOSE_NAV: {
          return {
            ...state,
            isOpen: state.isOpen - 1,
          };
        }
        default: {
          return state;
        }
      }
    };
    
    export default reducers;

    action type이 OPEN_NAV라면 isOpen값을 1 증가, CLOSE_NAV라면 isOpen값을 1 감소시켜 준다.

     

    4-3. store

    src/index.js

    // Redux 관련
    import { createStore } from "redux";
    import reducers from "./reducers";
    import { Provider } from "react-redux";
    
    // 스토어 생성
    const store = createStore(reducers);
    
    ReactDOM.render(
      <Provider store={store}>
        <Router>
          <App />
        </Router>
      </Provider>,
      document.getElementById("root")
    );

    reducer를 바탕으로 store를 생성하고 프로젝트에 store 적용 

     

    4-4. Nav 컴포넌트에 적용

    실제 컴포넌트에 리덕스를 적용하기 위해 class형에 적용하는 방법과 함수형에 hooks를 사용하여 적용하는 방법이 있는데 두 가지 모두 사용해보니 함수형이 훨씬 간단하였다.

    import React, { useState, useCallback } from "react";
    import { useDispatch } from "react-redux";
    import { Link } from "react-router-dom";
    import * as actions from "../actions/nav";
    
    const Nav = () => {
      const dispatch = useDispatch();
      const [navCheck, setNavCheck] = useState(0);
    
      const openNav = useCallback(() => {
        setNavCheck(navCheck + 1);
        dispatch(actions.openNav());
      }, [navCheck, dispatch]);
    
      const closeNav = useCallback(() => {
        setNavCheck(navCheck - 1);
        dispatch(actions.closeNav());
      }, [navCheck, dispatch]);
      
      .
      ..
      ...

    이후 return 부분에서 state 값이 1로 변경되면 메뉴가 열리고, 0으로 변경되면 메뉴가 없어지게 만들었다.

     

    Review

    사실 nav 컴포넌트에 리덕스를 적용한 것은 너무 과했다고 느꼈다. 단순히 컴포넌트 내에서만 상태를 true, false에 변경에 따라 처리했을 때가 코드의 가독성도 좋고 길이도 훨씬 짧았다. 리팩토링을 거치면서 코드가 길어지고 복잡해지는 것을 직접 느껴보니 모든 부분에 리덕스를 적용하는 것은 비효율적이라는 것을 느끼게 되었다. 전역 상태로 처리해야 하는 부분에만 적용하는 것이 코드를 명확하고 깔끔하게 만든다는 것 생각이 들었다.

     

     

     

    댓글