본문 바로가기
카테고리 없음

[Redux] 무작정 시작하기 (2) - 간단한 예제

by 허도치 2020. 4. 24.

2020/04/23 - [Font-end/Javascript] - [Redux] 무작정 시작하기 (1) - Redux란?

 

 

 

서론

  지난 포스트에서 Redux에 대해서 간단하게 정리해보았다. 상태관리가 복잡한 클라이언트 사이드 렌더링에서  많이 사용되는데 실제 예제를 통해 어떻게 사용되는지 알아보도록 하자.

 

 

 

1. Redux 프로세스

  Redux는 단 1개의 저장소(Store)를 가지고 있다. 이 저장소에 저장된 상태(State)불변가변성(Immutable)의 성격을 지니는데, 이를 변경하려면 미리 정의된 행동(Action)리듀서(Reducer)에게 요청(Dispatch)해야한다. 그러면, 리듀서는 요청받은 행동과 상태를 확인하고, 상태를 복제하여 새로운 상태값을 적용한다. 처리가 완료되면 저장소를 구독(Subscribe)하고 있는 모든 구독자들에게 상태의 변경을 알린다.

 

 

 

2. Redux 설치

  Redux 설치는 npm으로 설치하는 것을 권장하지만, Node를 사용하지않거나 간단하게 적용하기에는 CDN을 사용하는게 제일 좋다.

 

2-1. Package Download
npm install redux

 

2-2. CDN
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.js"></script>

 

 

 

3. 예제

  버튼을 클릭하면 입력된 텍스트에 해당 색상을 적용하여 출력하는 예제이다. 하나의 파일에 작성하다보니 소스가 조금 길어져서, 가독성을 위해 html과 script 작성 파트를 나누어서 다루어 보도록 하겠다.

 

3-1. HTML 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
  </head>
  <body>
    <div id="root">
      <div id="worktable"></div>
      <div id="controller">
        <input type="text" id="input_text" value="" placeholder="Change Text">
        <div class="btn-groups">
          <button class="btn change-text" value="red">red</button>
          <button class="btn change-text" value="blue">blue</button>
        </div>
      </div>
    </div>    
    <!-- Redux -->
    <script type="text/javascript">
      /** Action, Reducer, Store **/
    </script>
    <script type="text/javascript">
      /** Subscribe, Dispatch **/
    </script>
    <!-- Redux -->
  </body>
</html>
cs

 

 

 

3-2. Script 작성 - Action, Reducer, Store
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/** Action Types **/
var CHANGE_TEXT = "example/CHANGE_TEXT";
 
/** Reducers **/      
function changeTextReducer(state, action){
  console.clear();
  console.group("[State]");
  console.log("[previous]", state);
  console.group("[action]");
  console.log("[type]", action.type);
  console.log("[payload]", action.payload);
  console.groupEnd("[action]");
  
  var newState = Object.assign({}, state);
  
  if( state === undefined ){
    /** State Initialize **/
    newState = {
      text: "State Initialize",
      color: "black"
    };
  } else if( action.type === CHANGE_TEXT ){
    newState = Object.assign(newState, {
      color: action.payload.color,
      text: action.payload.text
    });
  }
  
  console.log("[next]", newState);
  console.groupEnd("[State]");
  
  return newState;
}
 
/** Store **/
var store = Redux.createStore(
  changeTextReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
cs

1) [ 2 ln ] - Action의 Type을 정의

    : Action Type은 Dispatch와 Reducer가 소통하기 위한 매개체.

 

2) [ 5 ln ] - Reducer( State, Action )

    : Reducer는 Dicpatch로 부터 State와 Action을 전달 받으며, Action의 Type에 따라 State를 처리함.

 

3) [ 6~12 ln, 29~30 ln ] - Logging

    : 이전 상태와 현재 상태를 출력하기 위한 Logger.

 

4) [ 14 ln ] - State 복제

    : 앞서 소개했듯이 Redux의 State는 불변가변성(Immutable)의 성격을 가지기 때문에, 직접적으로 State를 갱신하는 것이 아니라 복제하여 갱신하는 방법을 사용.

5) [ 16~21 ln ] - 초기값 설정

    : Store가 생성될 때 Reducer가 한번되며, 이 때 비어있는 State에 초기값을 채워넣을 수 있음.

6) [ 22~21 ln ] - Action Type에 따른 처리 로직

    : Dispatch로부터 받은 Action Type과 갱신할 상태값(Payload)를 받아서 State를 갱신하는 로직을 작성.

    : Dispatch에서 Payload를 아무리 많이 보내도 이곳에서 처리하지 않는다면 Store에 저장되지 않음.

 

7)  [ 36~39 ln ] - Store 생성

     : Store는 첫번째 인자로 Reducer를 받으며, 이 때 받은 Reducer를 통해서만 State를 갱신할 수 있음.
     : 여러개의 Reducer를 사용하는 경우, Redux.combineReducers()를 통해 결합하여 등록할 수 있음.
     : 두번째 인자로는 Middleware를 받는데, Redux를 개발할 때 State의 흐름을 파악하기위한 Redux DevTools를 등록.

 

 

3-3. Script 작성 - Subscribe, Dispatch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/** Subscribers **/
function ChangeText(){
  var state = store.getState();
  
  document.querySelector("#worktable").innerHTML = `
  <h3 style="color: ${ state.color }">${ state.text }</h3>
  `;
}
store.subscribe(ChangeText);
 
/** Dispathcers **/
function dispatchChangeText(event){
  event.preventDefault();
  
  var color = event.target.value;
  var text = document.querySelector("#input_text").value;
  
  store.dispatch({
    type: CHANGE_TEXT, 
    payload: { 
      color,
      text,
    }
  });
}
 
/** Event Binding **/
Array.from(document.querySelectorAll(".btn.change-text")).forEach((element)=>{
  element.removeEventListener("click", dispatchChangeText);
  element.addEventListener("click", dispatchChangeText);
});
cs

1) [ 3 ln ] - Store에 저장되어 있는 State 가져오기.

2) [ 5~7 ln ] - State를 이용하여 생성한 Text Element를 '#worktable'에 추가.

3) [ 9 ln ] - Store를 구독(Subscribe)
    : Store의 State가 변경될 때마다 ChangeText 함수가 실행됨.

 

4) [ 18~24 ln ] - Dispatch를 실행
    : State를 갱신하는 로직을 결정하는 Action의 Type과 갱실한 값(Payload)를 인자로 전달.

 

5) [ 28~31 ln ] - 버튼에 Dispatch 이벤트를 Handler로 바인딩

 

 

 

4. 실행화면

[ 실행 로그 ]

  위와 같이 텍스트를 입력하고 버튼을 클릭하면 색상이 적용되는 것을 확인할 수 있다. 이 때, 로그를 확인해보면, 맨 처음 실행되었을 때 State에 초기값이 저장된 것이 확인되고 이후 값을 텍스트를 입력하고 클릭할 때 마다 State가 변경되면서 출력화면도 변경된다.

 

 

 

마치며

  Redux를 간단한 예제를 통해 알아보았다. 역시 먼저 이론적으로 다가가는 것보다는 직접 만들어 보는게 이해하기가 더 수월했던 것 같다. Redux는 React를 만들 때 많이 사용했는데 이렇게 개별적으로 사용해보니 나름 유용하게 쓸 수 있을 것 같다. 지난번에 2048 게임을 만들 때 상태값 때문에 애를 좀  Redux를 적용해서 리펙토링을 시도해봐야겠다.

댓글