index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="./index.css" />
</head>
<body>
<div class="toggle"></div>
<hr />
<h1>0</h1>
<button id="increase">+1</button>
<button id="decrease">-1</button>
<script src='./index.js'></script>
</body>
</html>
index.css
.toggle {
border: 2px solid black;
width: 64px;
height: 64px;
border-radius: 32px;
box-sizing: border-box;
}
.toggle.active {
background: yellow;
}
index.js
import { createStore } from "redux";
const divToggle = document.querySelector(".toggle");
const counter = document.querySelector("h1");
const btnIncrease = document.querySelector("#increase");
const btnDecrease = document.querySelector("#decrease");
1. 액션 타입과 액션 생성 함수 정의
(...)
// 프로젝트의 상태에 변화를 일으키는 것을 액션이라 하고, 액션에 이름을 정의한다.
// 액션 이름은 문자열 형태로, 주로 대문자로 작성하며 액션 이름은 고유해야 한다.
const TOGGLE_SWITCH = "TOGGLE_SWITCH";
const INCREASE = "INCREASE";
const DECREASE = "DECREASE";
//다음으로 이 액션 이름을 사용하여 액션 객체를 만드는 액션 생성 함수 작성
//액션 객체는 type 값을 반드시 갖고 있어야 한다.
//increase의 경우 difference 파라미터에 원하는 값을 추 후 적용
const toggleSwitch = () => ({ type: TOGGLE_SWITCH });
const increase = (difference) => ({ type: INCREASE, difference });
const decrease = () => ({ type: DECREASE });
2. 초깃값 설정
(...)
const initialState = {
toggle: false,
counter: 0,
};
3. 리듀서 함수 정의
(...)
// 리듀서는 변화를 일으키는 함수이다. 함수의 파라미터로는 state와 action 값을 받아 온다.
// state가 undefined일 때는 initialState를 기본값으로 사용
function reducer(state = initialState, action) {
//action.type에 따라 다른 작업을 처리함
switch (action.type) {
case TOGGLE_SWITCH:
return {
...state,
toggle: !state.toggle,
};
case INCREASE:
return {
...state,
counter: state.counter + action.difference,
};
case DECREASE:
return {
...state,
counter: state.counter - 1,
};
default:
return state;
}
}
//리듀서에서는 상태의 불변성을 유지하면서 데이터에 변화를 일으켜 주어야 한다. 이 작업을 할 때 spread 연산자를 사용하면 편하다.
4. 스토어 만들기
(...)
const store = createStore(reducer);
5. render 함수 만들기
(...)
//render 함수는 상태가 업데이트될 때마다 호출되며, 리액트의 render 함수와는 다르게 이미 html을 사용하여 만들어진 UI의 속성을 상태에 따라 변경해준다.
const render = () => {
const state = store.getState(); // 현재 상태를 불러온다.
// 토글 처리
if (state.toggle) {
divToggle.classList.add("active");
} else {
divToggle.classList.remove("active");
}
// 카운터 처리
counter.innerText = state.counter;
};
render();
6. 구독하기
(...)
//이제 스토어의 상태가 바뀔 때마다 방금 만든 render함수가 호출되도록 해준다. 이 작업은 스토어의 내장 함수 subscribe를 사용하여 수행할 수 있다.
//subscribe 함수의 파라미터로는 함수 형태의 값을 전달해 준다 이렇게 전달된 함수는 추후 액션이 발생하여 상태가 업데이트될 때마다 호출된다.
store.subscribe(render);
7. 액션 발생시키기
(...)
//액션을 발생시키는 것을 디스패치라고 한다. 디스패치를 할 때는 스토어의 내장 함수 dispatch를 사용한다. 파라미터는 액션 객체를 넣어 주면 된다.
//다음과 같이 각 DOM 요소에 클릭 이벤트를 설정하여 이벤트 함수 내부에서는 dispatch 함수를 사용하여 액션을 스토어에게 전달한다.
divToggle.onclick = () => {
store.dispatch(toggleSwitch());
};
btnIncrease.onclick = () => {
store.dispatch(increase(2));
};
btnDecrease.onclick = () => {
store.dispatch(decrease());
};
참고 - 리액트를 다루는 기술(김민준)