티스토리 뷰
리액트 프론트 앤드 개발자를 하면서 리덕스는 꽤나 중요한 축에 속해진다.
하지만 러닝커브가 길기 때문에 처음부터 많이 적용할 수도 없고, 적용을 많이 못하였던 것이 필자의 현실이었다.
그리고 다시 공부를 하면서 조금 깊게 파기 위해 리덕스가 무엇인지,
왜 필요하여 많이 쓰이는지에 대해 진득하게 정리를 해보기 위해 이 글을 쓰게 되었다.
왜 리덕스인가?
가장 궁금한 것 중 하나는 왜 리덕스를 쓰는 지다.
사실 찾으면 찾을수록 당연히 필요하다고 느낄 수 있지만, 처음 접한 사람에게는 이것이 굳이 왜?라는 기분이 들 수 있다.
리덕스는 쉽게 말하면 상태 관리를 의미한다.
리덕스를 사용하기 위해서
리덕스를 사용하기 위해 최소한의 설치는 다음과 같다.
node, npm OR yarn
필자가 느끼기엔 이것이 가장 최소한의 필요한 것이다. 노드는 npm 패키지를 자동으로 설치를 해준다. 그리고 yarn의 경우 npm이 설치가 되면 yarn 패키지 또한 설치가 가능하다.
npm install --global yarn
node를 설치하게 되면 npm을 통해 yarn을 설치할 수 있다.
추가적으로 github, vscode를 설치하게 되면 좀 더 관리 및 코드 작성이 편리해진다.
리액트 애플리케이션 만들기
기본적으로 리덕스를 사용하기 위해서는 리액트 앱을 설치해야 한다. 설치 명령어는 다음과 같다.
npx create-react-app vanilla-redux
OR
yarn create react-app vanilla-redux
위 명령어 둘 중 하나를 입력해도 된다.
TMI
여기서 조금 더 찾아보신 분들은 npm, npx, yarn 이 세 가지 명령어를 보신 분이 계실 것이다.
npm : 자바스크립트 런타임 환경 Node.js의 기본 패키지 관리자이다.
npx : npm 5.2.0 버전부터 새롭게 추가된 하나의 도구로, npm에서 귀찮은 과정들을 단순화하는 도구이다.
yarn : 안전하고 안정적이며 재현 가능한 프로젝트이다.
더 자세한 내용은 추후 따로 정리할 예정이다.
다음으로는 VanillaJS에 대해 공부한 내용을 토대로 작성을 해보려고 한다. 참고한 강의는 노마드코더에 초보자를 위한 리덕스 101이다.
VanillaJS Counter
JavaScript의 한 종류로 브라우저를 통해 제공된 JavaScript이다. 먼저 리덕스를 알기 전에 바닐라 JS로 간단한 count함수를 구현하였다.
//index.js
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
let count = 0;
number.innerText = count;
const updateText = () => {
number.innerText = count;
};
const handleAdd = () => {
count = count + 1;
updateText();
};
const handleMinus = () => {
count = count - 1;
updateText();
};
add.addEventListener("click", handleAdd);
minus.addEventListener("click", handleMinus);
코드가 실행되는 순서(혹은 읽는 순서)는 다음과 같다.
1) getElementById를 통해 ID값(add, minus)을 가져온다.
2) addEventListener를 통해 클릭 이벤트를 생성하고 함수(handleAdd, handleMinus)를 실행한다.
3) 함수 안에 코드를 실행한다.
이렇게 크게 3단계로 보면 될 것 같다.
위에 바닐라 JS코드를 리덕스화 하는 과정을 진행해보려 한다. 먼저 리덕스를 사용하기에 앞서 설치할 패키지는 다음과 같다.
yarn add redux
OR
npm install redux
설치를 한 후 아래와 같은 코드를 작성한다.
Vanilla Redux Counter
//index.js
import { createStore } from "redux";
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
const countModifier = () => {
return "hello"
};
const store = createStore(countModifier);
console.log(countStore); // {dispatch: f, subscribe: f, getState: f, replaceReducer: f}
Store
이 프로젝트의 state가 되는 data를 넣는 곳이다. 여기서 state는 프로젝트에서 application에서 바뀌는 data를 의미한다. 즉, 애플리케이션을 통해 변하는 값들을 store에 저장을 하는 공간을 의미한다. 위 VanillaJS에서는 count의 함수만이 state가 되는 것이다. 여기에서 store은 4개의 함수를 가지게 된다.
Reducer
프로젝트의 data를 modify를 하는 것으로, 의미를 찾고 수정하는 함수라고 한다. 여기서 만약 countStore.getState로 콘솔을 변경하게 되면 hello를 리턴하게 된다.
1) 리듀서는 data를 수정을 한다.
// ...
const countModifier = (state) => {
console.log(state); // undefined 가 발생
return state;
};
const store = createStore(countModifier);
만약 이렇게 변경을 할 경우, console에서는 undefined값이 나오게 된다.
// ...
const countModifier = (state = 0) => {
console.log(state); // 0
return state;
};
const store = createStore(countModifier);
// OR : 둘 다 같은 값을 호출한다.
// ...
const countModifier = (state = 0) => {
return state;
};
const countStore = createStore(countModifier);
console.log(countStore.getState()); // 0
하지만 state값에 0이라는 것을 default를 하게 되면 처음에 아무 값이 없어도 console은 0 값을 호출하게 된다. 즉, state를 initializing(초기화)을 한다.
Action
redux에서 function을 부를 때 사용하는 두 번째 parameter 혹은 argument이다.
//index.js
import { createStore } from "redux";
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
const countModifier = (count= 0, action) => {
return (count, action); // 0, {type: "@@redux/INITy.f.4.n.p"}
};
const countStore = createStore(countModifier);
일단 아무것도 진행하지 않은 상태에서 action값만 넣게 될 경우, 위 주석처럼 매우 이상한 값을 가져오는 것을 알 수 있다.
//index.js
import { createStore } from "redux";
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
const countModifier = (count= 0, action) => {
return (action); // 0, {type: "@@redux/INITy.f.4.n.p"}
};
const countStore = createStore(countModifier);
countStore.dispatch({ type: "HELLO" }); // {type: "HELLO"}
dispatch에 type을 정의할 경우 다음과 같은 값을 console에 호출하는 것을 볼 수 있다.
{type: "@@redux/INIT..."}
{type: "HELLO"}
현재 countModifier은 두 번 부른 상태가 된다.
아래와 같은 코드를 한번 실행해보도록 했다.
//index.js
import { createStore } from "redux";
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;
}
};
const countStore = createStore(countModifier);
countStore.dispatch({ type: "ADD" });
countStore.dispatch({ type: "ADD" });
countStore.dispatch({ type: "ADD" });
countStore.dispatch({ type: "ADD" });
countStore.dispatch({ type: "ADD" });
countStore.dispatch({ type: "MINUS" });
console.log(countStore.getState());
위의 코드를 실행할 경우 console는 다음과 같은 코드로 반환하는 것을 볼 수 있다.
처음에는 기본 값 count = 0, action = init값이 먼저 저장이 된 후 ADD를 dispatch를 통해 호출하면 ADD type에 맞게 count 함수가 증가한다. 그리고 MINUS type일 때는 count -1이 실행되어 최종적으로 state에 있는 값은 4가 되는 것을 알 수 있다.
아래 이미지는 모두 동일한 코드로 add라는 ID값을 가진 태그를 찾아 그 태크를 클릭 시 handleAdd를 실행하여 count에 +1을 진행한다.
그렇게 되면 다음과 같은 현상을 확인할 수 있다.
subscribe
프로젝트가 우리에게 store안에 있는 변화를 알 수 있게 해 준다.
//index.js
import { createStore } from "redux";
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
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;
}
};
const countStore = createStore(countModifier);
const onChange = () => {
console.log("there was a change on the store");
};
countStore.subscribe(onChange);
const handleAdd = () => {
countStore.dispatch({ type: "ADD" });
};
const handleMinus = () => {
countStore.dispatch({ type: "MINUS" });
};
add.addEventListener("click", handleAdd);
minus.addEventListener("click", handleMinus);
만약 이 코드를 실행하게 되면, ADD, MINUS버튼 모두 클릭 시 console.log를 반환하는 것을 알 수 있다.
우리가 또 다른 확인을 할 수 있는 방법은 다음과 같다.
//index.js
// 중략
const onChange = () => {
console.log(countStore.getState());
};
countStore.subscribe(onChange);
// 중략
이렇게 변경을 할 경우 우리가 원하던 count함수를 제대로 실행이 되는 것을 확인할 수 있다. 하지만 실제 화면에는 출력이 되지 않기에 화면에 텍스트를 뿌려주는 innerText값을 넣어주면 된다.
//index.js
// 중략
const onChange = () => {
number.innerText = countStore.getState();
};
countStore.subscribe(onChange);
// 중략
그렇게 우리는 count에 리덕스를 적용한 JavaScript를 만든 것이다.
이렇게 오늘은 VanillaJS와 Redux를 공부하였고, 정리를 하게 되었다.
혼자 독학으로 공부해서 실제로 적용을 해본 결과 쉽진 않았다. 그래서 다시 공부하게 되었는데...
다시 내 코드를 보게 되면 이해를 할 수 있기를 바라며 오늘도 이 글을 마치려 한다.
추가적으로 오류가 있거나 피드백을 주시면 감사히 보고 수정 조치하겠습니다.
감사합니다.
'Front-End > Javascript' 카테고리의 다른 글
초보자를 위한 리덕스 101 : 초기 리덕스 설정 시도해보기 (0) | 2021.07.28 |
---|---|
초보자를 위한 리덕스 101 : switch (0) | 2021.07.24 |
자바스크립트 유효성 검사 모음 (0) | 2021.06.19 |
URI 스키마 : 익스플로러에서 다른브라우저로 열리게 하기 (3) | 2021.06.12 |
자바스크립트에서의 배열 : Array (0) | 2021.04.13 |
- Total
- Today
- Yesterday
- 프로그래머스
- 리액트
- Coding Test
- 리액트 썸네일
- react
- 리액트 유튜브
- 리덕스
- 함수
- node
- 노드
- github
- java
- 파이썬
- 뷰
- node.js
- 자바
- Switch
- javascript
- array
- 코딩테스트
- 자바스크립트
- programmers
- redux
- Visual Studio Code
- Git
- CSS
- 배열
- 재공부
- node-sass
- mongodb
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |