본문 바로가기

Redux

VanillaJS → Redux | Redux 101 (1/2)

반응형

Redux | NomardCoder

- 기본적으로 javascript application들의 state를 관리하는 방법

- react와 redux는 별개임 (vue, angular, js 등 원하는 곳에서 다 사용가능)

 

 

**수업진행방식**

 

 1) redux와 vanilla javascript

 2) redux와react (react-redux)

 

1. redux없이 vanillaJS

+ ) vanillaJS를 redux로 바꾸기

2. redux없이 react

+) react를 redux로 바꾸기 (react-redux)

 

- redux가 왜 만들어졌고, 왜 redux를 사용해야하는지 - application을 어떻게 향상시키는지

- redux가 필요한 이유를 알기위해, redux없이 application을 실행해보고 redux에 그 아이디어를 더해보는 방식으로 진행할 것

 

 

* Pure Redux : Counter 

 

1. redux없이 vanilla JS - count 만들기

 

const add = document.querySelector("#add");
const minus = document.querySelector("#minus");
const number = document.querySelector("p");

let count = 0;
number.innerHTML = count;

const handle = () => {
  number.innerHTML = count;
};

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

const handleMinus = () => {
  count = count - 1;
  handle();
};

add.addEventListener("click", handleAdd);
minus.addEventListener("click", handleMinus);

 

 

- redux를 사용하기 위해서 npm install redux 명령어 실행

- redux에서 create store -> import하기 import { createStore } from 'redux';

store은 나의 data를 넣는 곳이다 = 나의 state (=application에서 바뀌는 data)

 

=> redux는 나의 data를 관리하는데 도와주는 역할을 하기 위해 만들어짐

 

import { createStore } from "redux";

const reducer = () => {};

//store만들기
const store = createStore(reducer);

 

- reducer은 함수고, 나의 data를 modify함 (count를 plus하거나 minus하는 것)

- reducer의 첫번쨰 인자는 state(스토어의 이전상태), 두번쨰 인자는 action(객체)을 받는다

 

import { createStore } from "redux";

const countModifier = () => {
  return "hello";
};

//store만들기
const countStore = createStore(countModifier);
console.log(countStore);

 

- store 출력시 아래와 같음

**!! 중요 !!**

 

import { createStore } from "redux";

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

//store만들기
const countStore = createStore(countModifier);
console.log(countStore.getState());

// 0 

 

정리 - createStore은 store을 create하고, store은 data를 저장하는 곳

- store을 만든다면 store에 countModifier을 줘야한다(redux에서는 reducer라고 불리움)

- default로 data modifier은 현재의 state와 함께 불려짐 (count=0)

 

 

2. 어떻게 count를 modify하는지 - action

- action은 redux에서 function을 부를때 쓰는 두번째 parameter or argument이다

 

import { createStore } from "redux";

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

//store만들기
const countStore = createStore(countModifier);

countStore.dispatch({ type: "add" });
countStore.dispatch({ type: "add" });
countStore.dispatch({ type: "add" });
countStore.dispatch({ type: "add" });
countStore.dispatch({ type: "minus" });
countStore.dispatch({ type: "minus" });

console.log(countStore.getState());
//2

 

 

3. subscription

 

import { createStore } from "redux";

const add = document.querySelector("#add");
const minus = document.querySelector("#minus");
const number = document.querySelector("p");

number.innerHTML = 0;

//reducer
const countModifier = (count = 0, action) => {
  console.log(count, action);
  if (action.type === "add") {
    return count + 1;
  } else if (action.type === "minus") {
    return count - 1;
  } else {
    return count;
  }
};

//store
const countStore = createStore(countModifier);

//subscribe
const onChange = () => {
  //getState
  number.innerHTML = countStore.getState();
};

countStore.subscribe(onChange);

//dispatch
const handleAdd = () => {
  countStore.dispatch({ type: "add" });
};

const handleMinus = () => {
  countStore.dispatch({ type: "minus" });
};

add.addEventListener("click", handleAdd);
minus.addEventListener("click", handleMinus);

 

 

dispatch(action) = store과 communication하는 역할 (add, minus)

(action -  변경할 내용 object / 따로 action 함수를 만들어서 dispatch에 넣는것이 코드 최적화에 좋음)

subscribe = store을 subscribe (쉽게말해 변화를 감지)

getState = initial 출력 (변화된 count를 출력)

 


 

Recap

- countModifier은 현재상태의 application과 함께 불려지는 function (count = 0)

- +action과 함께 불려짐, action은 countModifier소통하는 방법

- countModifier가 return하는 것은 (= reducer이 return하는 것) = apllication의 state가 됨

=> reducer은 current state와 action이 함께 불려진다!

 

- reducer에게 action을 보내려면? -> dispatch를 사용해서 보냄 (action은 object이어야함, 무조건 type이 있어야함(string X))

- change의 변화를 감지하고 싶으면? -> subscribe하기

 

 


Refactoring

 

import { createStore } from "redux";

const add = document.querySelector("#add");
const minus = document.querySelector("#minus");
const number = document.querySelector("p");

number.innerHTML = 0;

const ADD = "add";
const MINUS = "minus";

//reducer
const countModifier = (count = 0, action) => {
  switch (action.type) {
    case ADD:
      return count + 1;
    case MINUS:
      return count - 1;
    default:
      return count;
  }
};

//store
const countStore = createStore(countModifier);

//subscribe
const onChange = () => {
  //getState
  number.innerHTML = countStore.getState();
};

countStore.subscribe(onChange);

//dispatch
const handleAdd = () => {
  countStore.dispatch({ type: ADD });
};

const handleMinus = () => {
  countStore.dispatch({ type: MINUS });
};

add.addEventListener("click", handleAdd);
minus.addEventListener("click", handleMinus);

 

- if else문 -> switch문으로 변경

- 그냥 string을 바로 사용하기 보다, 실수의 위험을 줄이기 위해 constant변수를 사용하자(오류를 쉽게 찾을 수 있음)

 

 

* Pure Redux : To Do List 

 

1. redux없이 vanillaJS - toDoList

 

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

const paintToDo = (text) => {
  const li = document.createElement("li");
  ul.appendChild(li);
  li.innerHTML = text;
};

const handleSubmit = (event) => {
  event.preventDefault();
  const todo = input.value;
  input.value = "";
  paintToDo(todo);
};

form.addEventListener("submit", handleSubmit);

 

 

2. redux로 상태 변화하기

 

import { createStore } from "redux";

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

const ADD_TODO = "ADD_TODO";
const DEL_TODO = "DEL_TODO";

const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, { text: action }];
    case DEL_TODO:
      return [];
    default:
      return state;
  }
};

const store = createStore(reducer);

store.subscribe(() => console.log(store.getState()));

const handleSubmit = (event) => {
  event.preventDefault();
  const todo = input.value;
  input.value = "";
  store.dispatch({ type: ADD_TODO, text: todo });
};

form.addEventListener("submit", handleSubmit);

 

- state.push() -> 이런식으로 mutation을 사용하면 안됨, 상태를 수정하는 것이 아니라 새로운 것을 return하기

 

 

3. deletToDo

 

const deletToDo = (event) => {
  const id = event.target.parentNode.id;
  store.dispatch({ tyep: DEL_TODO, id });
};

//reducer
const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, { text: action.text, id: Date.now() }];
    case DEL_TODO:
      return state.filter((toDo) => toDo.id !== action.id);
    default:
      return state;
  }
};

↓ 코드 최적화 ------------------------------------------------------------------------

const deletToDo = (id) => {
  return {
    type: DEL_TODO,
    id,
  };
};

//reducer
const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, { text: action.text, id: Date.now() }];
    case DEL_TODO:
      return state.filter((toDo) => toDo.id !== action.id);
    default:
      return state;
  }
};

const dispatchDeletToDo = (event) => {
  const id = parseInt(event.target.parentNode.id);
  store.dispatch(deletToDo(id));
};

 

- 코드 최적화를 위해 코드를 분리할 수 있다 - 보통 reducer 위에 action 함수를 만듦

- filter 사용으로 state mutation 사용하지 말고, 새로운 배열 return

'Redux' 카테고리의 다른 글

Redux Toolkit  (0) 2021.05.05
[Redux 강의노트] Redux Middleware | redux-saga  (0) 2021.01.13
[Redux 강의노트] Redux Middleware | logger, thunk  (0) 2021.01.09
[Redux강의노트] Redux  (0) 2021.01.03
React → Redux | Redux 101 (2/2)  (0) 2020.11.24