본문 바로가기
웹 프론트엔드/React 리액트 (기초)

[React] 리덕스(redux) 기능으로 데이터 관리하기 ③ 코드 분리

by 지구인한군 2020. 10. 23.

 리덕스 첫 기초 포스팅에서는 개념을 파악하기 위해 모든 기능을 하나의 소스 코드에 넣었습니다. 즉 액션 정의, 리듀서 설정, 스토어 생성 등의 코드가 모두 한 곳에 있었습니다. 또한 하나의 리듀서를 사용하여 스토어 저장소도 나눠져 있지 않았습니다.

 

그래서 이번에는 코드를 분리하고 복수의 리듀서를 사용해 보겠습니다. 시간을 절약하기 위해 지난 시간에 했던 카운드 업 로직에 로그인 정보를 저장하는 정도의 기능을 추가하겠습니다. 아래 링크를 참고하세요~!

 

[Web프론트엔드/리액트] - [React] 리덕스(redux) 기능으로 데이터 관리하기 ① 기초

 

 먼저 액션을 분리해보겠습니다. src/components 폴더 안에 actions 폴더를 만들고 이하 두 개의 소스를 추가합니다.

 

// ..\test_project\src\components\actions\countActions.js

// 액션 타입 정의
export const SET_COUNT = 'countReducer/SET_COUNT';
export const RESET_COUNT = 'countReducer/RESET_COUNT';

// 액션 함수 정의
export const setCount = arg => ({
    type: SET_COUNT,
    data: arg,
});
export const resetCount = () => ({
    type: RESET_COUNT,
    data: { count: 1, isTen: false },
});

 

// ..\test_project\src\components\actions\loginActions.js

// 액션 타입 정의
export const SET_LOGIN = 'loginReducer/SET_LOGIN';

// 액션 함수 정의
export const setLogin = arg => ({
    type: SET_LOGIN,
    data: arg,
});

 

 액션은 간단합니다. 리듀서와 연결하기 위해 액션 타입을 정의하고 dispatch()에서 사용할 액션 함수를 만듭니다. countReducer, loginReducer와 연결하기 때문에 명시적으로 이름을 붙여서 타입을 만들었습니다. 그럼 리듀서를 만들기 위해 액션처럼 src/components 폴더 안에 reducers 폴더를 만들고 이하 세 개의 소스를 추가합니다.

 

// ..\test_project\src\components\reducers\countReducer.js

// 액션 타입 불러오기
import { SET_COUNT, RESET_COUNT } from "../actions/countActions";

// 데이터 정의 및 초기화
const initState = {
  count: 1,
  isTen: false,
};

// 초기화 데이터로 리듀서 만들기
export default function reducer(state = initState, action) {
  const { type, data } = action;
  switch (type) {
    case SET_COUNT: {
      return {
        ...state,
        ...data,
      };
    }
    case RESET_COUNT: {
      return {
        ...state,
        ...data,
      };
    }
    default:
      return state;
  }
}

 

// ..\test_project\src\components\reducers\loginReducer.js

// 액션 타입 불러오기
import { SET_LOGIN } from "../actions/loginActions";

// 데이터 정의 및 초기화
const initState = {
  id: "",
  pass: "",
  setLogin: function () {},
};

// 초기화 데이터로 리듀서 만들기
export default function reducer(state = initState, action) {
  const { type, data } = action;
  switch (type) {
    case SET_LOGIN: {
      return {
        ...state,
        ...data,
      };
    }
    default:
      return state;
  }
}

 

// ..\test_project\src\components\reducers\index.js

import countReducer from './countReducer';
import loginReducer from './loginReducer';

// 리듀서 모아서 내보내기
export default {
    countReducer,
    loginReducer,
};

 

 위에서 만든 액션을 불러와 리듀서에 붙여 줍니다. 중요한 부분은 state 데이터를 정의하고 초기화하는 부분인데 이렇게 리듀서 별로 만들어 놓으면 알기도 쉽고 조작하기도 편합니다. 실제로 사용하는 상위 소스에서도 다시 초기화가 가능합니다. 세 번째 소스인 index.js는 리듀서를 모아서 다음에 설명할 리덕스 스토어 생성에 사용하기 위함입니다.

 

// ..\test_project\src\components\reduxCreateStore.js

import { createStore, combineReducers } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import reducers from './reducers';

// 리덕스 스토어 생성
export default initStates => createStore(
    combineReducers(reducers),  // 리듀서 결합
    initStates,                 // 스테이터스 초기화
    composeWithDevTools(),      // 디버깅 미들웨어
);

 

 마지막으로 리덕스 스토어를 생성하는 부분입니다. 위에서 만든 리듀서 모음을 불러들여 combineReducers() 함수를 이용해 결합해줍니다. 세 번째 인자는 바로 지난 시간에 했던 리덕스 디버깅 툴과 연결하는 부분입니다. 미들웨어라고 하는데 추후에 따로 포스팅하겠습니다. 그럼 모든 준비가 끝났으니 실제로 적용을 해볼 차례입니다.

 

// ..\test_project\src\components\CountUpRedux_new.js

import React, { PureComponent } from "react";
import { Provider } from "react-redux";
import reduxCreateStore from "./reduxCreateStore";
import { setCount, resetCount } from "./actions/countActions";
import { setLogin } from "./actions/loginActions";
import Text from "./Text";
import Button from "./Button";

class CountUpRedux_new extends PureComponent {
  constructor(props) {
    super(props);

    // 콜백 함수 바인딩
    this.countUp = this.countUp.bind(this);
    this.resetCount = this.resetCount.bind(this);
    this.setLogin = this.setLogin.bind(this);

    // 로그인 리듀서 초기화
    const initStates_login = {
      id: "corona",
      pass: "dead4444",
      setLogin: this.setLogin, // 콜백 함수 연결
    };

    // 커스터마이징 함수로 스토어 생성
    this.store = reduxCreateStore({ loginReducer: initStates_login });
  }

  countUp() {
    // 스토어 데이터
    const data = this.store.getState();

    // 숫자 증가
    const countTemp = data.countReducer.count + 1;
    let isTenTemp = data.countReducer.isTen;

    // 10이상이면 true
    if (countTemp >= 10) isTenTemp = true;

    // 액션 함수로 데이터 저장
    this.store.dispatch(setCount({ count: countTemp, isTen: isTenTemp }));

    // 강제 갱신 (state 변경이 없어서)
    this.forceUpdate();
  }

  resetCount() {
    this.store.dispatch(resetCount({ count: 1, isTen: false }));
    this.forceUpdate();
  }

  setLogin() {
    this.store.dispatch(setLogin({ id: "아이디없음", pass: "ojimasio" }));
    this.forceUpdate();
  }

  render() {
    // 프로바이더를 사용하여 자식에게 데이터 전달
    const data = this.store.getState();
    return (
      <Provider store={this.store}>
        <React.Fragment>
          <Text>숫자값 : {data.countReducer.count}</Text>
          <br />
          <Text>10이상 : {String(data.countReducer.isTen)}</Text>
          <br />
          <Button name="countUp" onClick={this.countUp}>
            카운트
          </Button>
          <Button name="resetCount" onClick={this.resetCount}>
            리셋
          </Button>
          <br />
          <Text>ID : {data.loginReducer.id}</Text>
          <br />
          <Text>PASS : {data.loginReducer.pass}</Text>
          <br />
          <Button name="login" onClick={data.loginReducer.setLogin}>
            로그인
          </Button>
        </React.Fragment>
      </Provider>
    );
  }
}

export default CountUpRedux_new;

 

 지난 시간에 했던 카운트 업 로직 그대로이며 간단하게 id, pass 데이터를 추가한 정도입니다. 중요한 부분은 생성자에 reduxCreateStore() 하는 곳입니다. 초기화하고 싶은 리듀서만 선택해서 데이터를 넣어주고 있습니다. 리듀서가 두 개 이기 때문에 데이터를 불러올 때도 countReducer와 loginReducer로 나눠져 있습니다. dispatch() 부분도 액션에 만들었던 함수를 사용하고 있습니다. 기초 시간에 했던 소스에서 많이 정리가 됐습니다. 그럼 스토리북 확인해보시죠!

 

카운트 업 초기 상태

 

카운트 업 버튼 조작

 

 오른쪽 위의 디버깅 툴 화면 처럼 액션 타입 이름이 리듀서 별로 나눠져 있고 아래 State탭 정보 또한 두 개의 리듀서로 나눠져 있는 것이 확인 가능합니다. 이렇듯 코드를 분리하는 것 뿐만이 아니라 스토어 저장 공간을 리듀서 별로 나누고 관리를 하면, 리덕스의 강력한 기능을 조금 더 효율적으로 사용 가능합니다. 그럼 다음 포스팅으로 또 뵙겠습니다~!?

 

ㅇ ㅏ~ 힘들다...


2020/10/27 - [Web프론트엔드/리액트] - [React] 리덕스(redux) 기능으로 데이터 관리하기 ④ 해시맵

댓글