이 글에서는 바닐라 자바스크립트에서 리덕스를 사용하는 기본 방법에 대해 소개한다. 리덕스는 react나 vue, angular 등의 라이브러리 혹은 프레임워크와 결합해서 사용하는 게 일반적이지만, 일단은 리덕스 자체에 집중하기 위해 일반 자바스크립트를 사용했다.
프로젝트 세팅
우선 바벨이나 모듈 등의 설정을 위해서 Create-react-app(CRA)을 사용했다. CRA는 react 앱을 만들기 위해 여러 세팅을 간편하게 해주는 아주 유용한 앱이다. (홈페이지- https://create-react-app.dev/docs/getting-started )
프로젝트를 생성하자.
npx create-react-app my-app
cd my-app
npm start
그리고 바닐라 자바스크립트 사용을 위해 src/ 내에 index.js를 제외한 모든 파일을 삭제하고 index.js 파일은 비웠다.
이제리덕스를 이용해서 간단한 카운터 기능 만들어보자.
스토어 세팅
우선 데이터를 저장할 스토어를 생성하자.
import { createStore } from "redux";
const reduxReducer = function (state = 0, action) {
switch (action.type) {
case "INCREASEMENT":
return state + action.payload;
case "DECREASEMENT":
return state - action.payload;
default:
return state;
}
};
let reduxStore = createStore(reduxReducer);
- createStore | 스토어를 생성하는 함수. 인자로 reducer을 받음
- reducer | 전송 받은 데이터 변경 요청(action)에 따라 상태값을 변경하는 함수
- 인자 state | 최초의 상태 값
- 인자 action | view로부터 전송받는 데이터 변경 요청을 담은 객체
- 리듀서의 규칙
- 기존 상태값은 불변성을 유지해야 한다
- 반환되는 값이 새로운 상태값이 된다.
- 리듀서 내에서는 비동기 작업이나 다른 사이드 이펙트를 만들어선 안된다. 즉, 순수 함수이어야 한다.
- 외부 상태에 의존하는 작업(ex: math.random(), Date.now() ..)은 액션 생성자에서 작업 후 전달하자.
- 컨셉 | 단일 스토어, 단일 리듀서를 지향하는 리덕스는 하나의 스토어와 리듀서만을 두는 것이 일반적이다. 단, 앱이 방대해짐에 따라 리듀서가 방대해지면 메인 리듀서를 하위 리듀서로 분할하는 방식을 취한다.
- 팁 | 리듀서에서 액션을 분기처리하는 로직은 swith 문을 사용하면 편하다.
구독 설정
자바스크립트를 기반으로 하는 리덕스는 상태값 변경 시 자동으로 view를 업데이트하는 자동 바인딩이 없다. 리엑트는 이를 자동으로 지원하지만, 그렇지 않을 때는 이를 세팅해줘야 한다. 아까의 코드에 추가해보자.
import { createStore } from "redux";
//@스토어에 사용할 reducer
const reduxReducer = function (state = 0, action) {
switch (action.type) {
case "INCREASEMENT":
return state + action.payload;
case "DECREASEMENT":
return state - action.payload;
default:
return state;
}
};
//@스토어
let reduxStore = createStore(reduxReducer)
//@ 바인딩 함수
const bindingUi = function (dom, state) {
if (!dom instanceof HTMLElement) return;
dom.innerText = state;
};
//@ 스토어를 구독함. 데이터 변경 시 콜백 함수를 호출
reduxStore.subscribe(() =>
bindingUi(임의의 컴포넌트, reduxStore.getState())
);
- store.subscribe(callback) | 스토어를 구독하여 데이터 변경을 감지한다. 감지 시, 등록된 콜백 함수를 실행한다.
- store. getState() | 스토어의 현재 값을 불러온다.
- 주의사항 | 리듀서 함수의 반환 값이 동일하거나 반환이 없어도 실행됨
상태 값 변경을 요청하기
스토어 만들기, 리듀서 설정, 구독 설정 이후에는 데이터 값을 변경해달라고 요청할 차례다. 이 때는 store의 dispather 메소드를 사용한다. 이 메소드는 인자로 할당된 객체를 스토어의 리듀서로 전달한다. 이 때, 이 객체에는 무엇을 변경할지(종류), 얼마나 변경할지(값)를 담는게 일반적이다. 다시 카운터 예시를 보자.
import { createStore } from "redux";
//스토어에 사용할 reducer
const reduxReducer = function (state = 0, action) {
switch (action.type) {
case "INCREASEMENT":
return state + action.payload;
case "DECREASEMENT":
return state - action.payload;
default:
return state;
}
};
//스토어
let reduxStore = createStore(reduxReducer)
// 바인딩 함수
const bindingUi = function (dom, state) {
if (!dom instanceof HTMLElement) return;
dom.innerText = state;
};
//스토어를 구독함. 데이터 변경 시 콜백 함수를 호출
reduxStore.subscribe(() =>
bindingUi(임의의 컴포넌트, reduxStore.getState())
);
//html에서 가져온 버튼
const addButton = document.querySelector("button.add")
const minusButton = document.querySelector("button.minus")
//버튼 클릭 시, dispatch로 action 전송
addButton.addEventListener("click,()=>reduxStore.dispatch({type:"INCREASEMENT",payload:2}))
addButton.addEventListener("click,()=>reduxStore.dispatch({type:"DECREASEMENT",payload:2}))
- store.dispath(action) | 스토어의 리듀서로 데이터 변경을 요청함
- action | 데이터 변경 요청을 담은 객체, 일반적으로 type과 payload로 요청을 명시한다.
- 팁 | action.type은 오타를 방지하기 위해 상수타입의 변수를 만들어 관리하면 편하다.
- 팁 | action은 직접 객체를 생성하기 보단, 액션을 생성하는 함수를 별도로 만들어주는 게 일반적이다. 이를 액션생성자라 부른다.
액션 생성자의 예시
function actionAddCounter(payload) {
return {
type:"INCREASE",
payload:payload
}
정리
- 리덕스의 세팅 | 스토어 생성, 리듀서 설정, 구독
- 스토어와 리듀서는 단일로 설정하는 것이 리덕스의 컨셉에 맞음
- 앱이 커지면 리듀서는 하위 리듀서로 분할하여 관리
- 리듀서의 처리 로직은 switch 문이 일반적
- 리듀서의 규칙
- 기존 상태값은 불변성을 유지해야 한다. (오류 방지)
- 반환되는 값이 새로운 상태값이 된다.
- 리듀서 내에서는 비동기 작업이나 다른 사이드 이펙트를 만들어선 안된다
- 상태 값 읽기 | store.getState()
- 상태값 변경 요청 | store.dispatch(action)
- action은 객체로 type, payload 명시가 일반적
- type은 상수타입 문자열을 따로 선언해주면 오타 방지
- 데이터 변경 시 콜백 함수 실행 | store.subsribe(callback)
- 리듀서 함수의 반환 값이 동일하거나 반환이 없어도 실행됨
참고 자료
Redux - 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너. | Redux
자바스크립트 앱을 위한 예측 가능한 상태 컨테이너.
ko.redux.js.org
'상태관리 라이브러리 > Redux' 카테고리의 다른 글
[Redux] redux의 유지 보수 및 최적화 팁 3가지 (0) | 2024.03.22 |
---|---|
[Redux] 사용법부터 이론까지 살펴보는 Redux: 5. 입문자를 위한 createSlice 기본 세팅 소개 (0) | 2024.03.20 |
[Redux] 사용법부터 이론까지 살펴보는 Redux: 4. Redux-toolkit (0) | 2024.03.18 |
[Redux] 사용법부터 이론까지 살펴보는 Redux: 3. 리엑트에서의 사용 방법 (0) | 2024.03.18 |
[Redux] 사용법부터 이론까지 살펴보는 Redux: 1 기본 컨셉 (0) | 2024.03.17 |