본문 바로가기
Archive

Vanilla Javascript Redux 사용해보기 와 핵심개념

by livemehere 2022. 1. 26.
리덕스에 대한 오해

Redux는 React만을 위한 툴이 아닙니다.

저도 한때는 리액트를 위한 상태관리 라이브러리로 알고있었는데, 필요한 패키지들을 보면 redux, react-redux 이렇게 두가지이상을 설치하는것이 보일겁니다. 이때 redux를 그냥쓸수있는건가? 라는 생각이들었고, 공부하다보니 리덕스는 자바스크립트를 위한 툴이었습니다.

 

사실 react를 위한 툴이라고생각하는 이유는(vue..등 다른 라이브러리,프레임워크 포함), SPA로 설계하지 않은 웹 사이트는 javascript를 모듈화하지 않고 사용하기 때문이 아닌가라는 생각이 듭니다. 굳이 필요성을 못느낀 것이죠.

 

하지만 뭐든지 배울땐 최소한의 조건, getting started부터 배워야한다 생각합니다.

Vanilla JS 부터 React 까지 redux를 사용하는 예시와 개념을 살펴보겠습니다.(react에서 다루는 것은 따로 포스팅하겠습니다)

 

Vanilla JS Redux 샘플코드

index.html

  <body>
    <h1>Vanilla JS redux</h1>
    <span class="count">0</span>
    <button class="add">add</button>
    <button class="minus">minus</button>
  </body>

 

index.js

import { createStore } from "redux";

const addBtn = document.querySelector(".add");
const minusBtn = document.querySelector(".minus");
const count = document.querySelector(".count");

const ADD = "increase";
const MINUS = "decrease";

const reducer = (state = 0, action) => {
  console.log(state, action);

  switch (action.type) {
    case ADD:
      return state + 1;
    case MINUS:
      return state - 1;
    default:
      return state;
  }
};
const countStore = createStore(reducer);

countStore.subscribe(() => {
  console.log("countStore is changed!", countStore.getState());
  count.innerHTML = countStore.getState();
});

addBtn.addEventListener("click", () => {
  countStore.dispatch({ type: ADD });
});
minusBtn.addEventListener("click", () => {
  countStore.dispatch({ type: MINUS });
});

Redux Three Principles 중 중요한 2가지

1. store에저장된 state변경은 오직 reducer의 action을 통해서만 해야합니다.

2. Do not Mutation(state를 직접 변형하지 말것)

Mutation 예시

state를 직접 변형해서는 안됩니다. 대신 새로운 objects를 return 해야합니다.

Vanilla Javascript Todo With Redux

index.html

보기좋으려고 mvp.css 와 bootstrap 사용하여 클래스가 난해해 보입니다.

    <h1>Vanilla JS Redux TODO</h1>
    <form class="d-flex align-items-center mx-auto justify-content-center">
      <input type="text" class="d-flex mb-0" placeholder="new todo">
      <button class="py-1">ADD</button>
    </form>
    <ul>
    </ul>

index.js

import { createStore } from "redux";

const form = document.querySelector("form");
const input = document.querySelector("input");
const ul = document.querySelector("ul");

const reducer = (state = [], action) => {
  // console.log(action);
  switch (action.type) {
    case "ADD":
      return [...state, createNewTodo(action.payload)];
    case "REMOVE":
      return removeTodo(state, action.payload);
    default:
      return state;
  }
};

const store = createStore(reducer);

store.subscribe(() => {
  updateUI(store.getState());
  console.log(store.getState());
});

form.addEventListener("submit", (e) => {
  e.preventDefault();
  store.dispatch({ type: "ADD", payload: input.value });
  input.value = "";
});

function createNewTodo(text) {
  return {
    id: Date.now(),
    text: text,
  };
}

function removeTodo(todos, targetId) {
  const newTodo = todos.filter((todo) => todo.id !== targetId);
  return newTodo;
}

function updateUI(todos) {
  ul.innerHTML = "";
  todos.forEach((todo) => {
    const li = document.createElement("li");
    const button = document.createElement("button");
    button.addEventListener("click", () => {
      store.dispatch({ type: "REMOVE", payload: todo.id });
    });
    button.setAttribute("class", "py-1");
    button.textContent = "삭제";
    li.setAttribute("class", "list-unstyled");
    li.textContent = todo.text;
    li.appendChild(button);
    ul.appendChild(li);
  });
}

결과물

핵심

1. store의 state 접근은 오로지 reducer의 action을 통해서 할수있다.

2. state를 변경할때 절때 mutation하지 않고, 새로운 objects를 반환한다.

3. state의 변경을 감지하는 subscribe(callback)함수를 사용할 수 있다.

4. 라이브러리에서 오로지 createStore()함수 하나만 사용했다.

 

Github

https://github.com/livemehere/redux-study

 

GitHub - livemehere/redux-study: 바닐라 js 에서의 redux 사용 공부 및 todo 예시앱

바닐라 js 에서의 redux 사용 공부 및 todo 예시앱. Contribute to livemehere/redux-study development by creating an account on GitHub.

github.com

 

반응형