Vanilla Counter

Redux를 사용하기 이전에 JS로 버튼을 클릭하면 숫자가 카운팅되는 아주 가단한 프로그램을 작성할 것이다.

<button id="add">Add</button>
    <span>0</span>
<button id="minus">Minus</button>
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");

let count = 0;
number.innerText = count;

const setText = () => {
  number.innerText = count;
};

const handleAdd = () => {
  count += 1;
  setText();
};

const handleMinus = () => {
  count -= 1;
  setText();
};
add.addEventListener("click", handleAdd);
minus.addEventListener("click", handleMinus);

이렇게 만들어진 카운터 프로그램을 redux로 다시 리펙토링하는 프로그램을 만들어 볼 것이다.


Store and Reducer

이제 프로젝트에 redux를 설치하여 createStore을 추가해 본다. 여기서 createStore은 개발자가 사용하는 data를 저장하는 기능을 하며 data를 관리측면에서 state라고 부른다. 또한 state는 프로그램에서 바뀌는 data를 가르킨다.

그럼 위 작성한 코드에서 data가 바뀌는 것이 무엇이 있을까? 바로 count 이다. 그리고 나머지 함수들은 변하는 데이터가 아닌 count를 modify해주는 기능이기에 state라고 할 순 없다. 그러므로 count를 집중적으로 관리할 수 있는 함수인 redux의 createStore를 사용하여 state를 저장하는 store을 만든다.

import { createStore } from "redux";

const countModifier = (count = 0) => {
  console.log(count);
  return count;
};

const countStore = createStore(countModifier);

createStore은 reducer함수를 필요로한다. Store에 저장된 데이터를 제어하거나 modify할 수 있는 함수인 reducer말이다. 즉, 프로그램에 사용될 data는 store에 등록된 state이며 state의 상태를 변경 할 수 있는 유일한 통로가 reducer인 것이다.

Reducer는 전달 받은 인수로 reducer에 정의된 코드를 실행하는데 그 과정에서 state가 modify되고 반환된 state로 store은 등록된 state를 설정한다. 즉, 우리는 reducer가 modify한 state를 store.getState를 호출하여 설정된 state를 가져올 수 있게 된다. 위 코드에서 보인듯이 countModifier (reducer)에서 반환한 값이 countStore에 들어간 것으로 보이지만 실상은 store정보가 countStore에 들어간 것이고, createStore(store)의 getState를 통해서 state를 얻어와야 하는 것이다.


Actions

createSore에서 프로그램에 사용할 state을 얻어오는 방법을 알았냈다. 하지만 더욱 복잡한 코드를 구현하기 위해서는 다양한 조건으로 state를 가공해야한다. 가령 JS로 count를 ++, —하는 간단한 프로그램일 지라도 말이다. 그래서 다양한 동작을 하기위해 만들어진것이 reducer의 action파라미터이다. action 파라미터는 object type으로 property가 type : any으로 데이터를 받게 된다. 그리고 reducer는 action으로 들어온 type의 형태를 조건문으로 원하는 동작을 구현하면 된다.

import { createStore } from "redux";

const countModifier = (count = 0, action) => {
  const { type } = action;
  if (type === "ADD") {
    return (count += 1);
  } else if (type === "MINUS") {
    return (count -= 1);
  } else return count;
};

const countStore = createStore(countModifier);
coun  tStore.dispatch({ type: "ADD" });
console.log(countStore.getState());
countStore.dispatch({ type: "MINUS" });
console.log(countStore.getState());

이제 store에 등록된 reducer을 실행하는 함수인 dispatch를 호출하여 reducer를 동작하면된다. dispatch에는 reducer의 두번째 인자와 같은 object를 전달하여 reducer가 동작하면서 개발자가 정의한 기능을 수행하게 한다. 즉, state와 state를 제어하는 함수를 reducer에 정의하고 프로세스에서 store API로 data를 가지고 온다.