[스터디] #10 redux

ch9eri·2022년 11월 4일
1

멋사 프론트 스터디

목록 보기
10/12

🌟 Redux

Javascript application들의 state를 관리하는 방법

  • React와 많이 사용하면서 유명해졌으나, React에 의존하는 라이브러리는 아님
  • Angular, Vue.js, Vanilla JS 등 JS 언어내의 여러곳에서 사용 가능

Counter using vanillaJS

//index.html
<body>
    <button id="add">Add</button>
    <span></span>
    <button id="minus">Minus</button>
  </body>
//index.js
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
let count = 0;

number.innerText = count;

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

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

이렇게만 하면 count값은 변화하지만 화면에는 바뀐 값이 출력되지 않고 0으로만 뜬다

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

const handleAdd = () => {
  count = count + 1;
  updateText();
};
const handleMinus = () => {
  count = count - 1;
  updateText();
};

update 함수를 추가하고 다른 함수들을 실행할 때마다 같이 실행시켜주면 화면에도 바뀐 값이 출력된다

🧩 Redux 시작하기

yarn add redux

Store : data(state)를 저장하는 곳
CreateStore : reducer를 요구
Reducer : data를 modify 해주는 함수
-> reducer가 return하는 것이 application에 있는 data가 됨

import { createStore } from 'redux';

const reducer = () => {};
const store = createStore(reducer);

store을 만들면 reducer을 만들라는 요청 옴

오직 reducer만 data를 modify 가능

const reducer = (state = 0) => {
  return state;
};

console.log(store.getState());

state를 0으로 initializing

→ action을 통해 state를 modify

🧩 Action

redux에서 function을 부를 때 쓰는 두번째 parameter로 reducer와 소통하기 위한 방법

const countStore = createStore(reducer);

countStore.dispatch({type:"ADD"});

Reducer에게 Action을 보내는 방법

💡 store.dispatch({key: value});

dispatch : reducer에게 message 보내기

const reducer = (count = 0, action) => { //count = 0 : 현재 state
  if (action.type === 'ADD') {
    return count + 1;
  }
  else if (action.type === 'MINUS') {
    return count - 1;
  }
  else
    return count;
};

const countStore = createStore(reducer);

countStore.dispatch({type:"ADD"});
countStore.dispatch({type:"ADD"});
countStore.dispatch({type:"MINUS"});

current State : 0 → 1 → 2 →1 이런 식으로 변화

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

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

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

아까처럼 handleAdd, handleMinus 함수 만들어서 연결하기

→ ❗️ 화면 출력되지 않는 현상 발생

🧩 Subscribe

store 안에 있는 변화 감지

💡 store.subscribe(func);

store안의 변화를 감지하면 func 실행

const countStore = createStore(reducer);

const onChange = () => {
  number.innerText = countStore.getState();
}

countStore.subscribe(onChange);

countStore의 변화를 감지해서 onChange를 실행 → 화면 출력

개선,보안할 것

1. Switch문

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

리덕스에서는 if-else보다 switch를 자주 사용한다?

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

2. Const Variable

string을 바로 쓰는 대신 const variable로 선언해서 사용하기 -> 에러 발견 용이

const ADD = "ADD";
const MINUS = "MINUS";

case ADD:
      return count + 1;
case MINUS:
      return count - 1;

TODO using vanillaJS

배열을 만들어 추가하고 삭제하고 하는 것 불편 ! → 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 DELETE_TODO = 'DELETE_TODO';

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

const store = createStore(reducer);

const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = '';
  store.dispatch({ type: ADD_TODO, text: toDo });
};

form.addEventListener('submit', onSubmit);

counter 때와 비슷하게 구현

🌟⚠️🌟⚠️🌟⚠️🌟⚠️

💡 state mutate(변형) 금지

대신 new state objects를 리턴

→ 금지❌

state는 single source of truth이며, read-only이다

🌟 store을 수정할 수 있는 유일한 방법은 action을 보내는 방법뿐이다.

ADD TODO

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

const store = createStore(reducer);
store.subscribe(() => console.log(store.getState()));

return [...state, { text: action.text, id: Date.now() }];

→ ES6 문법 : …

array의 이전 컨텐츠에 새로운 object 합쳐서 새 array 만들기

DELETE TODO

filter() : 조건을 만족하는 element들로 새로운 array를 만든다

state.filter(toDo => toDo.id !== action.id);

toDo 안에 있는 element와 다른 id를 가진, 즉 선택되지 않은 element들로만 새로운 array 생성

전체 코드

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 DELETE_TODO = 'DELETE_TODO';

const addToDo = text => {
  return {
    type: ADD_TODO,
    text
  };
};

const deleteToDo = id => {
  return {
    type: DELETE_TODO,
    id
  };
};

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

const store = createStore(reducer);

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

const paintToDos = () => {
  const toDos = store.getState();
   ul.innerHTML = "";
   toDos.forEach(toDo => {
     const li = document.createElement("li");
     const btn = document.createElement("button");
     btn.innerText = "DEL";
     btn.addEventListener("click", dispatchDeleteToDo);
     li.id = toDo.id;
     li.innerText = toDo.text;
     li.appendChild(btn);
     ul.appendChild(li);
   });
};

store.subscribe(paintToDos);

const dispatchAddToDo = text => {
  store.dispatch(addToDo(text));
}

const dispatchDeleteToDo = (e) =>  {
  const id = parseInt(e.target.parentNode.id);
  store.dispatch(deleteToDo(id));

};

const onSubmit = (e) => {
  e.preventDefault();
  const toDo = input.value;
  input.value = '';
  dispatchAddToDo(toDo);
  
};

form.addEventListener('submit', onSubmit);
profile
잘하자!

0개의 댓글