FE develop/redux

Redux를 써먹어보자

hoj0806 2024. 3. 16. 20:12

리덕스란?

리덕스는 자바스크립트의 상태관리 라이브러리로써 특히 리액트의 state를 쉽게 관리하게 만들어주는 라이브러리이다 이 게시물에서는 바닐라 JS 에서 리덕스를 다루는법을 살펴보고자한다

 

 

 

바닐라 JS로 배워보는 redux

간단한 카운터앱을 만들면서 redux를 배워보자

 <btutton id="add">Add</button>
 <span>0</span>
 <button id="minus">Minus</button>
 <button id="reset">Reset</button>

Add 버튼을 누르면 카운터가 하나씩 증가하고 minus를 누르면 카운터가 하나씩 감소, reset 버튼을 누르면 카운터가 0이되는 간단한 카운터앱이다

 

 

 

 

바닐라 JS에서 리덕스를 사용하기 위해서는 cdn을 설치해줘야한다 다음과 같은 코드를 head 태그에 삽입해주자

<script
      src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.js"
      integrity="sha512-aU+9st6E3LYPknXJiOkhUXxYz/QbB1IDf1YUYzCCbgiwOCu2g/1pH+68ROdxC3clouCOVfO6u2g7qoB43rfmQg=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
 ></script>

 

 

 

 

 

 

그리고 body 태그 맨밑에 script 태그를 열고 자바스크립트 코드를 작성해보자
우선 DOM을 통해 버튼과 카운터값을 표시하는 요소를 가져오자

const add = document.getElementById("add");
const minus = document.getElementById("minus");
const reset = document.getElementById("reset")
const number = document.querySelector("span");

 

 

 

 

 

리덕스를 사용하기 위해서 가장 먼저 필요한것은 store를 만들어 주는것이다 우리가 핸들링하기 위한 데이터를 담을 저장소라고 생각하면 편하다 store를 만드는 방법은 createStore 메소드를 통해 만들어주면 된다

const store = Redux.createStore()

 

 

 

 

 

자 이제 스토어가 만들어졌다 스토어안에는 꼭 reducer를 넣어줘야하는데 reducer는 데이터를 초기화하고 그 데이터를 수정하는 action들을 정할수 있는 함수이다

const initState = 0
const reducer = (state = 0 , action) => {

}

 

리듀서 함수에는 두가지 파라미터가 들어가는데 첫번째는 우리가 저장할 데이터이다 해당 코드에는 카운터의 초깃값인 0을 default값으로 정해줬다 두번째는 action인데 action의 type에 따라 state가 어떻게 변할지 정의할수 있다 가장 중요하게 짚고 넘어가야할점은 reducer로 정의한 state는 무조건 여기서 정의한 action으로만 그 값을 수정할수있다 자 그렇다면 action의 type을 지정해보자

 

 

 

 

const ADD = 'ADD';
const MINUS = 'MINUS';
const RESET = 'RESET';

const reducer = (state = initState, action) => {
         switch(action.type) {
          case ADD :
            return state + 1
            break
          case MINUS :
            return state - 1
            break
          case RESET:
            return 0
            break
          default:
            return state
        }
      }

각각의 타입을 위에서 상수로 지정해 안에 문자열을 담아줬다 switch문을 통해 작성했는데 action의 type이 'ADD'일경우 state를 +1한뒤 리턴하고 있다 나머지 기능도 swtich문을 통해 넣어준다 action의 type까지 지정해줬으면 이제 dispatch를 사용해서 action의 type을 dispatch라는 메소드를 통해 return 해줘야한다 여기서는 add버튼을 눌렀을때 카운터값이 + 1되는 기능만 구현해보자

 

 

 

 

const addCount = () => {
        return { type : ADD }
 }

 const addDisPatch = () => {
         store.dispatch(addCount())
 }

  add.addEventListener('click' , () => {
        addDisPatch()
  })

우선 addCount 함수를 통해 객체하나를 리턴해주는데 { type : 타입종류 }의 형식으로 리턴해준다 또 그렇게 리턴된 값을 addDisPatch를 함수를 통해 다시 넘겨받는다

 

그리고 dispatch를 통해 타입을 넘겨주어야한다 마지막으로 add 버튼에 이벤트리스너를 달아주면 완성이다 아까 리듀서 함수를 통해 state와 action타입에 따른 state의 변화를 지정해줬는데 dispatch 메소드가 실행될때마다 실행이된다 하나 알아두어야 할점이 있는데 리듀서 함수에서 state를 리턴할때 즉시 바뀐 state를 리턴하는것이 아닌 바뀌기전 state를 리턴한다

 

 

 

 const reducer = (state = initState, action) => {
        console.log(state)
         switch(action.type) {
          case ADD :
            return state + 1
            break
          case MINUS :
            return state - 1
            break
          case RESET:
            return 0
            break
          default:
            return state
        }
      }

위와 같이 코드를 작성하고 add버튼을 한번 누르면 상식적으로 state에서 1을 더한 1이 출력되야할것같지만 그렇지 않다 add 버튼을 누를때 state는 0에서 1로 바뀌었으므로 바뀌기전의 state값인 0이 출력된다 마찬가지로 버튼을 한번 더누르면 2가 출력되는게 아니라 1이 출력된다

 

 

 

아무튼 여기까지 했으면 거의 다왔다 마지막으로 state값이 변함에 따라 html요소에 state값을 넣어주기만 하면된다 현재 redux의 state값을 들고오기 위해서는 위에서 지정한 store에 getState 메소드를 사용해야한다

number.innerText = store.getState()

단순히 이렇게 코드를 작성하면 버튼을 눌렀을때 카운터값이 변화하지 않는다 redux에서 변화하는 state값을 감지하기 위해서는 subscribe 메소드를 사용해야한다 subscribe를 통해 state가 변할때마다 실행시킬 함수를 파라미터로 넣어주면된다

 

 

 

// 함수정의
const onChange = () => {
  number.innerText = store.getState()
}
// subscribe 사용
store.subscribe(onChange)

이렇게 하면 state값이 변할때마다 원하는 함수를 실행시킬수 있다

 

정리하면 store 지정 -> 리듀서 작성 ->

리듀서에 state 초기값, action type에 따른 state return(swtich문이나 if else 문 사용) ->

dispatch를 통해 action type 리턴 -> subscribe

의 흐름으로 리덕스를 사용하면 되겠다 다음 게시물에서는 react에서 redux를 사용하는 방법을 알아보자

 

 

 

전체코드

<html>
  <head>
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.js"
      integrity="sha512-aU+9st6E3LYPknXJiOkhUXxYz/QbB1IDf1YUYzCCbgiwOCu2g/1pH+68ROdxC3clouCOVfO6u2g7qoB43rfmQg=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>
  </head>
  <br>
    <button id="add">Add</button>
    <span>0</span>
    <button id="minus">Minus</button>
    <button id="reset">Reset</button>
    <script>


      const add = document.getElementById("add");
      const minus = document.getElementById("minus");
      const reset = document.getElementById("reset")
      const number = document.querySelector("span");

      const ADD = 'ADD';
      const MINUS = 'MINUS';
      const RESET = 'RESET';
      const initState = 0
      const reducer = (state = initState, action) => {
        console.log(state, action)
         switch(action.type) {
          case ADD :
            return state + 1
            break
          case MINUS :
            return state - 1
            break
          case RESET:
            return 0
            break
          default:
            return state
        }
      }
      const store = Redux.createStore(reducer)
      const addDisPatch = () => {
        let ADD = 'ADD'
         store.dispatch(addCount())
      }

      const minusDisPatch = () => {
        store.dispatch(minusCount())
      }

      const resetDisPatch = () => {
        store.dispatch(resetCount())
      }


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

      const addCount = () => {
        return { type : ADD }
      }

      const minusCount = () => {
        return { type : MINUS}
      }

      const resetCount = () => {
        return {type : RESET }
      }
      add.addEventListener('click' , () => {
        addDisPatch()
        console.log(store.getState());
      })

      minus.addEventListener('click', () => {
        minusDisPatch()
        console.log(store.getState());
      })

      reset.addEventListener('click', () => {
        resetDisPatch()
        console.log(store.getState());
      })
      store.subscribe(onChange)
         </script>
  </body>
</html>