[Redux] redux 기본 - redux를 활용하기 위한 구조 이해

Hyo Kyun Lee·2021년 8월 30일
0

Redux

목록 보기
1/9

1. Redux

data의 흐름을 일방향화 하여 산재되어있는 구조와 흐름을 정리해주고,
이에 따른 코드의 유지보수와 무결성을 높여주는 도구.

React와 이름이 비슷하여 혼동할 수 있으나, React와는 완전히 별개의 라이브러리이다.

2. javascript의 data 흐름

Redux를 활용하기 전 Javascript 코드의 data 흐름을 먼저 살펴본다.

//Vanilla

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

let count = 0

number.innerText = count

const updateCount = () => {
  number.innerText = count
}

const handleAdd = () => {
  count = count + 1
  updateCount()
}
const handleMinus = () => {
  count = count - 1
  updateCount()
}

add.addEventListener("click", handleAdd)
minus.addEventListener("click", handleMinus )
  • getElementId를 통해 각 버튼 tag와 add(count + 1), minus(count - 1) 함수를 연결해 주었다.
  • updateCount 함수를 통해 변화한 count를 실질적으로 html tag에 반영하여 화면에 구현해주는 logic을 추가하였다.

이 코드에서 변화하는 데이터 값인 count의 흐름을 나타내면 아래와 같다.

  • 단순히 EventListener를 통해 count를 +1, -1 해주었다 해도 화면에 구현되는 것은 아니다.
  • 변화한 데이터를 연결된 html tag에 반영하여, 화면에 구현해주도록 update까지 해주어야 반영된다.

3-1. Redux 활용을 위한 기본 개념

데이터를 저장하는 공간인 Store

  • Redux는 모든 data와 변화하는 상태값을 저장할 수 있는 store 공간이 존재한다.
  • 이 공간에 data를 담아 향후 수정, 관리 시 일괄/일방향적으로 할 수 있다.

Store와 같이 사용하는 reducer

  • redux와 같이 사용하는 reducer는 함수이다.
  • 이 reducer를 통해 data를 수정할 수 있다(유일한 수정기능을 제공하는 함수).

3-2. Store와 reducer을 활용하기 위한 기본 구조

Store(reducer) 구조

//Vanilla
import { createStore } from "redux"

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

const reducer = () => {
  return 
}
const countStore = createStore(reducer)
console.log(countStore)

위 코드와 같이 Store를 생성한 후 reducer 함수를 연결해주면,
reducer 함수 내부의 data 값들을 상태반영할 수 있고 수정할 수 있게 된다.

Store를 log 출력을 통해 확인해보면 4가지 함수를 얻을 수 있다.

위 코드를 통해 Store를 log한 결과는 아래와 같이 4가지 reducer 함수이다.

이 4가지 함수를 활용하여 복잡한 State 관리를 하나의 functional Programming을 통해 구현할 수 있다.

getState를 통해 application의 상태관리에 반영할 data값을 바로 선언할 수 있다.

const reducer = () => {
  return "HELLO"
}
const countStore = createStore(reducer)
console.log(countStore.getState)

특히 위와 같이 reducer 함수의 return 값에 반환할 문자열을 나타내주고 getState 함수를 활용하여 log를 확인하면

reducer 함수의 반환 값을 그대로 전달받을 수 있고, 이 상태값이 application의 data 값으로 그대로 반영된다.

Reducer를 통해 state를 update하고,
이를 return해서 createStore에 전달하여 data 변화 및 상태관리를 구현할 수 있다.

import {createStore} from 'reducer'

const reducer = (state) => {
	modify state
    return state.value
}

createStore(store.getState)

위와 같은 구조로 data를 변화하여 상태반영하고 이 반영한 상태값을 getState를 통해 전달해주면, 상태반영된 data값 즉 변화한 data값을 바로 활용할 수 있게 된다.

※ 유의할 점은 const reducer라는 함수는 사용자가 직접 정의해주어야 하며, 다만 createStore가 상태값을 그대로 받아올 수 있도록 구조에 유의하며 logic을 구성해야 한다.

4. action

reducer와 외부에서 소통하기 위해 만든 reducer 함수의 두번째 인자

const reducer = (state = initial_value, action) => {
	return state
}

정리하면 선언한 reducer 함수 내에서

  • state를 받아와 initializing을 해주고
  • 이를 return해주어 Store에서 해당 값을 getState하여, application의 상태값을 전달해주는 구조를 살펴보았으며
  • 지금부터는 action 인자를 추가하여 외부에서 상태값을 변화시킬 수 있으며, 어떻게 변화할 수 있는지 그 과정을 알아본다.

4-1. reducer에게 두번째 인자로 전달되는 함수이자, reducer와 소통하는 경로

reducer 함수는 state와 action을 전달받을 수 있다.

const reudcer = (state = initial_value, action) 

createStore는 기본적으로 4가지 함수를 가지고 있고,
이 중 dispatch 함수를 이용하면 해당 action을 reducer에게 전달할 수 있다.

위에서 보았듯이 createStore가 자체적으로 가지는 함수는 4가지가 있고,

  • getState는 Store 내부에 선언되어있는 상태값을 불러오는 함수
  • 지금 활용할 dispatch는 reducer의 action 인자에 해당하는 객체/명령을 전달하여 reducer 함수 내에서 action을 활용할 수 있도록 도와주는 기능 제공
  • 위에서 기술하였듯 action을 통해 reducer와 소통할 수 있는 창구가 생긴 셈이다.
const reducer = (state = 0, action) => {
  console.log(action)
  return state
}
const countStore = createStore(reducer)

countStore.dispatch({dispatced_action : "HELLO"})

위 logic 흐름을 살펴보면

  • countStore을 통해 Store를 생성하였고, 여기에 reducer 함수를 넣어 해당 state와 action을 store로 연결해주었다.
  • Store를 통해 선언된 reducer가 최초로 호출되어, state 값이 initial_value인 0으로 선언되고 action을 전달받는다(해당 action은 Store로 부터 받은 객체가 출력됨).
  • 그 후 Store를 통해 dispatch(action)이 호출되어 reducer가 다시 작동하고 action이 reducer에게 최종적으로 전달된다.
  • action 이후의 반영된 상태값, 즉 data가 return 되어 Store에 반영된다.

※ 유의할 점은 dispatch를 통해 전달하는 객체 값 자체가 action으로 default된 값이고, 이 action이 전달될 때 reducer가 호출된다.

즉, 외부에서 reducer를 호출하여 내부의 값을 수정할 수 있다.

이는 기본적으로 createStore를 통해 reducer와 store를 연결해주었기 때문에 가능한 구조라는 것을 잊지말자.

4-2. (참조) reducer와 action의 "소통"으로 data를 바꾸는 과정

const reducer = (state = 0, action) => {
  if(action.type === "ADD"){
    state = state + 1
  }
  if(action.type === "MINUS"){
    state = state - 1
  }
  console.log(state)
  return state
}
const countStore = createStore(reducer)

countStore.dispatch({type : "ADD"})

위 코드를 실행하게 되면

위와 같이 0, 1이 차례대로 나온다.

  • 최초 Store를 생성하면서 reducer를 연결, 이때 0으로 선언된 state value가 log출력.
  • 그 후 dispatch를 통해 reducer가 한 번 더 호출되면서 변화한 state값이 return되어 log 출력.

외부에서 reducer를 호출하여 내부 data 값을 변화시킬 수 있었다.

4-3. (참조) action을 통한 data 바꾸는 원리

여기서 의문이 들 수 있는데, 최초 reducer가 호출되었을 때 바로 state값을 바꾸면 되지 않나는 생각이 들 수 있다.

결론부터 말하면 바꿀 수 있다.

action의 핵심은 reducer와의 소통, 외부에서 reducer를 호출할 수 있다는 점이다.

이는 dispatch를 통해 action 호출 시 reducer가 한 번 더 호출되는 원리에 기반하여 작동하기 때문에 가능한 것임을 기억하자.

0개의 댓글