반응형

Redux에 대해 알아보기

그동안 전역 상태관리를 위해 recoil로 충분히 사용이 가능했지만, redux 또한 놓칠 수 없는 개념이기에 학습하고 정리하는 내용을 작성해본다.
먼저 관련된 키워드와 내용에 대해 알아보고, 사용법을 알아보고자 한다.

🔹Action

액션은 Reducer와 소통하는 존재이다.
변화가 일어나면 액션이라는 것이 발생하는데, 구분자 형태로 사용된다.

액션 작성 규칙
-액션은 객체(Object)형태로 작성해야한다.
-객체 내부에는 type이라는 필드를 필수적으로 가지고 있어야 한다.

🔹ActionCreator

액션 객체를 만들어주는 함수이다.
해당 함수는 액션을 만들어주다보니 당연히 Object형태를 반환하고 type 필드를 가진다.
그 외에 동작할 명세를 작성한다.

const changeInput = (text:string) => ({
  type: "CHANGE_INPUT",
  text
});

🔹Reducer

변화를 일으키는 함수다.
현재 상태와 전달받은 액션 객체 파라미터를 받는다.
두 개의 값을 비교하여 새로운 상태를 반환한다.
구분자할 값이 많아지면 비교적 if문보단 switch문이 가독성이 좋아서 switch를 사용한다.

const initialState = {
    counter: 1
}
function reducer(state=initialState, action){
    switch(action.type){
        case "INCREASE":
        return state.counter+1
    }
}

🔹Store

프로젝트에 store는 한 개를 가진다.
(여러개를 가질 수도 있지만 복잡해질 수 있음)
스토어에는 현재 어플리케이션의 상태와 리듀서가 들어간다.
그 외에 중요한 내장 함수들로 구성된다.

🔹Dispatch

리듀서에서 stateaction 두 개의 파라미터를 받는데, 여기서 reducer에게 action을 보내는 행위를 dispatch가 처리한다.
dispatch는 리듀서를 불러와서 current state와 내가 작성한 action을 처리한다.

🔹Subscribe

store에 등록된 값의 변화를 감지하다가 변화가 발생하면 콜백 함수가 동작한다.

🔹Vanilla-Redux

npm install redux
const { createStore } = require("redux");

const divToggle = document.querySelector(".toggle");
const counter = document.querySelector("h1");
const btnIncrease = document.querySelector("#increase");
const btnDecrease = document.querySelector("#decrease");

const TOGGLE_SWITCH = "TOGGLE_SWITCH";
const INCREASE = "INCREASE";
const DECREASE = "DECREASE";

/**
 * 액션을 가지고 액션 생성 함수를 작성한다.
 * type은 필수값으로 가지고 있어야하며 원하는 형태로 커스텀 할 수 있다.
 */
const toggleSwitch = () => ({ type: TOGGLE_SWITCH });
const increase = (difference) => ({ type: INCREASE, difference });
const decrease = () => ({ type: DECREASE });

// 초기값 설정
const initialState = {
    toggle: false,
    counter: 0,
};

/**
 * reducer defined.
 * 변화를 일으키는 함수다. state, action 두 개의 값을 받는다.
 */
function reducer(state = initialState, action) {
    switch (action.type) {
        case TOGGLE_SWITCH:
            return {
                // 불변성 유지를 위해 새로운 객체를 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;
    }
}

// store작성 리듀서 함수를 넣어준다.
const store = createStore(reducer);

/**
 * render함수 작성
 */
const render = () => {
    const state = store.getState();
    if (state.toggle) {
        divToggle.classList.add("active");
    } else {
        divToggle.classList.remove("active");
    }
    counter.innerHTML = state.counter;
};

render();
store.subscribe(render);

// 구독하기
// const listener = () => {
//     console.log("상태가 업데이트됨.");
// };
// const unsubscribe = store.subscribe(listener);
// unsubscribe();

divToggle.onclick = () => {
    store.dispatch(toggleSwitch());
};
btnIncrease.onclick = () => {
    store.dispatch(increase(1));
};
btnDecrease.onclick = () => {
    store.dispatch(decrease());
};
반응형