Redux - 리.덕.스

Sean yang~~·2023년 2월 13일
0
post-thumbnail

리.덕.스

채용공고를 훅훅 보다보면, 우대사항이나 필수사항에 항상 들어가는 것이다. 누군가는 항상 말했다. redux는 필수라고~~ 기업인턴을 가서도 항상 들었던 말이었다. 사용해보고싶지만, 선뜻 어렵고 복잡하다는 소리를 많이 들어서 시작도 하기전에 겁부터 먹고 하니, 머리에 잘 안들어오더라. 하지만, 공부는 해야되니까!!

시작해보자~~

리덕스를 사용하는 이유?

항상 우리는 어떤 프로젝트를 만들때, 사용할 언어 프레임워크 등등을 정하고 시작을 하는데, 그 전에 왜 꼭 그것을 사용해야 하는지가 첫번째이자 그리고 제일 중요한 문제이다.!

그래서~! 리덕스는 왜 사용해야 되는건데? 굳이 써야되나?? (쓰는게 좋을껄?? ㅋㅋ)

리덕스, 상태 관리(Managing State) 공식문서를 보면 이유가 친절히 설명이 되어 있다. 한 4가지 정도로 설명이 되어 있는데, 쨋든,

  • 리덕스는 중앙집중국??
    난 중앙난방이라고 비유하면서 이해했다. 이게 무슨말이냐하면, redux 는 store 라는 저장소를 만들수 있는데, 이 저장소 안에서 state를 관리하면서, 내가 원하는 컴포넌트로 쭉쭉 뿌려줄수가 있다는 것이다. 중앙난방에서 모든 아파트의 온돌을 관리하듯, store에서 전체 state를 관리 한다는 뜻이다.

  • 그리고 다른 이유로는 props 지옥에서 탈출할 수 있다~~ 🙌🙌🙌🙌
    리액트는 컴포넌트화가 되어있다보니, 최상위 부모에서 사용한 것을 자식의 자식의 자식의 자식에서 사용한다면 props 를 내리고 내리고 내리고 반복하게 된다.

이런 식으로 하다보면 헷갈릴 수도 있고, 실수가 나올 수도 있다. 이 것을 redux가 좀더 쉽게 도와준다. 왜냐하면 store에서 따로 관리를 하다보니 어느 위치에 있든 상관없이 단 한번에 상태를 받을 수 있기 때문이다.

위의 그림처럼 뿌려주는 형식이다.

만약 리덕스를 사용하지 않으면, 동작 하나하나에 다른 코드들과의 종속관계 즉, 연결고리가 많을 경우, 하나의 코드가 지워지면 에러를 발생키기게 된다.

리덕스를 사용하게 될 경우, 하나의 store에서 state를 뿌려주는 식으로 동작하기 때문에, 서로의 의존관계가 사라지게 됩니다. 따라서, 각자의 컴포넌트에 집중해서 작업을 할 수 있습니다. 즉, 디커플링.

Redux 아키텍쳐

  • store
  • state
  • action
  • reducer
  • subscription
  • view

업로드중..

store

Redux 스토어(store)는 애플리케이션의 상태를 관리하고, getState(), dispatch(), subscribe()
같은 메서드를 제공합니다.

import { createStore } from 'redux'

// Redux 스토어 생성
// - 리듀서 함수를 전달 받음
const store = createStore(reducer)

스토어는 애플리케이션의 상태를 나타내는 많은 key: value 쌍으로 구성된 정보를 가진 하나의 큰 Javascript 객체입니다. React 컴포넌트에 분산디어 있는 상태 객체와 달리 스토어는 하나만 존재합니다. 스토어는 애플리케이션에 상태를 제공하며 상태가 업데이트 되면 뷰(UI)가 다시 그려집니다.

state

Redux 스토어에서 관리하는 상태(데이터) 입니다.

// 상태
// - 일반적으로 state 또는 initState 이름으로 설정
// - 상태는 리듀서(함수)의 첫번째 인자로 전달 됨

// counter
const state = 0

// todos
const initState = []

상태 트리(state tree)는 '불변 상태(Immutable State). 즉 순수한 상태(건드리지말라!)를 가져야 한다. '

스토어에 등록된 상태 정보는 .getState() 메서드를 사용해 가져올 수 있다.

store,getState()

action

액션은 애플리케이션에서상태 변경을 설명하는 정보 를 스토어로 보내는 javascript 객체로 redux에 알려(dispatch) 변화를 이끌어 냅니다. 상태 값을 변경(교체) 할 경우, 교체할 상태 값(payload)을 리듀서(함수)에 보낼 수 있다.

// '카운트 증가' 상태 변경을 설명하는 액션
const increaseCountAction = { type: "INCREASE_COUNT"}

const decreaseCountAction = { type: "DECREASE_COUNT"}

const resetCountAction = { type: "DECREASE_COUNT", payload: 0}

애플리케이션 상태 트리를 변경하는 유이한 방법은 "액션을 보내는 것" 이다.

store.dispatch(action)

액션타입을 별도 관리하는 파일을 만들어 상수(constant)로 관리하는 것이 유지보수하기 좋다.

export const INCREASE_COUNT = 'INCREASE_COUNT'
export const DECREASE_COUNT = 'DECREASE_COUNT'
export const RESET_COUNT = 'RESET_COUNT'
import { INCREASE_COUNT, DECREASE_COUNT, RESET_COUNT} from './actionTypes'

export const increaseCountAction = () => ({ type: INCREASE_COUNT })
export const decreaseCountAction = () => ({ type: DECREASE_COUNT })
export const resetCountAction = () => ({ type: RESET_COUNT_COUNT, payload: 0 })

리듀서

모든 Redux 애플리케이션은 공통점이 있다. 바로 리듀서(reducer)를 구현해야 한다는 점이다.
리듀서란? '애플리케이션 상태를 교체하는 함수'를 말합니다. '이전 상태(prevState)' 를 '새로운 상태(state)' 로 교체 한다.

const reducer = (prevState = initState, action) {
  switch(action, type) {
    case INCREASE_COUNT:
      return prevState + 1
    case DECREASE_COUNT:
      return prevState - 1
    default:
      return prevState

리듀서는 상태와 액션을 전달 받아 '이전 상태' 를 '다음 상태' 로 교체한 후 반환한다. 즉, 리듀서는 '순수한 함수' 여야 한다.

리듀서 = (상태, 액션) {
  // 액션 타입 분석
  // 이전 상태 -> 다음 상태로 교체
  // 다름 상태 변환

순수한 함수란?

  • 순수 함수는 반환(return) 값이 전달 인자 (argument) 값에만 의존하는 함수를 말합니다.
  • 순수 함수는 새로운 값을 계산합니다. 동일한 유형의 인자 집합을 사용해 순수 함수를 호출하면 예측 가능한 결과 값을 확신할 수 있습니다.
  • 순수함수는 전달 된 인자 값을 변경하지 않습니다.
const square = x => x * x
const squareAll = item => item.map(sqauare)

리듀서(함수)는 순수해야 합니다. 순수함을 잃어버리면 사이트 이팩트(부작용)를 발생시킬 수 있습니다.

  • 전달 받은 매개변수 state, action에 변형을 가하면 안됩니다.
  • 네트워킹(API 호출 <- 비동기 통신) 또는 라우팅을 변경하면 안됩니다.
    반드시 반환 값은 새로운 상태(state) 입니다.

subscribe

애플리케이션 상태 변경을 구독(subscribe, 감지) 하여 상태가 업데이트 되면 등록된 리스너를 실행시킵니다.

store.subscribe(render)

.subscribe() 메서드는 구독을 취소할 수 있는 unscribe 함수를 반환합니다.

const unsubscribe = store.subscribe(() => console.log(`상태 변경 감지: ${store.getState()}`))

unsubscribe 함수를 실행하면 상태가 업데이트 되어도 UI를 업데이트 하지 않습니다.

unsubscribe() // 구독취소

Redux 작동방식

  1. createStore() 를 통해 Store 하는 하나의 저장공간을 만들고, state라는 객체를 생성한다.
let store = Redux.createStore(reducer);
  1. Callback 함수인 Reducer를 호출하여 state 값을 초기화 한다.
function reducer(state, action){ // state는 이전 값, action은 바꿔주는 역할을 한다.
  if(state === undefined){
	// state의 값이 아직 세팅되지 않았으면 초기값은 (초기화를 위해) undefined 가 된다.  	
  }
}
  1. UI 내에 color 값을 변경하고 싶을때는, store.dispatch({type:"CHANGE_COLOR", state, color:"red"}) 을 생성하고, 인자값으로 dispatch를 호출한다.
let newState;
if(action.type === "CHANGE_COLOR") {
  newState = Object.assign({}, state, {color:'red'})
}
return newState;
  • state 값을 가져오려면 getState를 사용해야된다.
let state = store.getState()
  1. dispatch는 reducer를 호출하고, reducer는 파라미터로 기존 state와 action 값을 받는다.
  2. reducer는 action의 type에 따라 실행해야 할 명령문을 정한다. 이때 순수함수로 작성을 해야한다.
  3. store에 있는 state 값을 대체하는 것이 아니라, Object.assign으로 복제하여 새로운 state 값을 만들고, store 에 저장한다.
  4. store의 state 값이 변경되고 나면, dispatch가 subcribe(render)를 호출하여 render 안에 새로운 state 값을 전달함으로써 rendering이 된다.
profile
나는 프론트엔드 개발자다!

0개의 댓글