Redux 개념정리 (with node.js)

Redux는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너다.

Redux는 여러 컴포넌트에서 Globally 공유하는 데이터를 관리하기위해 사용한다.

큰 구성

  • Component
  • Action
  • Reducer
  • Redux Store

개념

  • Component에서 어떤 data에 변동이 생기면 Store에 반영시켜야하는데
  • 바로 directly 반영시키는게 아니라 Action과 Reducer를 통해서 한다.

  • Store에 state들이 들어있다. (global data)
  • Component에선 action을 dispatch하여 Store의 state를 변화시킨다.
    • dispatch시에 store의 reducer에 정의된 대로 state에 변화가 생김.
  • 그리고 Store를 subscribe하여서 변화를 감지한다.

Redux 모듈 메소드 리스트

const redux = require("redux");
console.log(redux);

위 코드를 통해 redux 오브젝트의 API를 확인해보면 다음과 같다.

  • redux.applyMiddleware()
  • redux.bindActionCreators()
  • redux.combineReducers()
  • redux.compose()
  • redux.createStore()

이렇게 5개 밖에 없으니 우선 알아만 두고

Redux 공식 API 레퍼런스 로 필요할때 찾아서 공부하자.

코드 속 구성

State

  • object 타입
  • 저장되고 변화되는 데이터 주체다.

Action

  • object 타입
  • type이라는 key를 가지고 있다.
    • Reducer에서 action을 받았을때 type을 통해 어떤 action인지 식별한다.
  • action object를 반환하는 function으로 정의하여 사용하기도 한다.

Reducer

  • function 타입
    • stateaction을 인자로 받는다.
  • action에 따라 변화된 state를 반환한다.
    • 이때, 인자로 받은 state의 immutability를 지키기 위해 spread operator(...) 를 이용해서 인자로 받은 state를 deep copy하여 사용한다.

Store

  • object 타입

  • redux.createStore(reducer) 메소드를 통해 생성된다.

    • 인자로 reducer를 받는다. (+ middleware도 받음)
  • store 메소드 정리

    • store.getState()
      • 현재 store에 저장된 state를 반환한다.
    • store.dispatch(action)
      • action obj를 인자로 받는다.
      • store 내부에서 해당 action을 실행시킨다.
        • reducer에 정의된 대로 실행됨.
    • store.subscribe(listener)
      • store에 변화가 생길때 마다(즉, dispatch를 할때마다), 콜백 listener 함수가 실행 된다.
    • store.replaceReducer(nextReducer)
      • 현재 store에서 사용하는 reducer를 교체한다.

데이터 흐름

  1. 컴포넌트에서 먼저 액션이라는 것을 dispatch 합니다.
  2. 이 action은 reducer를 호출 하고
  3. reducer는 조건에 맞춰서 state를 업데이트 해줍니다 (redux store)
  4. state가 바뀌면 그 스테이트를 get하고 있는 컴포넌트들이 조건에 맞춰 리렌더링 되게 됩니다. (혹은 새로 랜더링이 됩니다)

코딩 Example

간단하게 과일바구니 state를 redux로 관리하는 시뮬레이션을 해보겠다.

간단 예시

const redux = require("redux");

// actions
const addApple = () => {
    return {
        type: "ADD_APPLE"
    }
}

// reducers
const initState = {apple: 3};
const reducer = (state = initState, action) => {
    switch(action.type) {
        case 'ADD_APPLE':
            return {
                ...state,
                apple: state.apple + 1
            }
        default:
            return state;
    }
}

// store
const store = redux.createStore(reducer);

// subscribe - view - dispatch
console.log(store.getState());
store.dispatch(addApple());
console.log(store.getState());
store.dispatch(addApple());
console.log(store.getState());
  • 결과

store.subscribe() 이용

  • 맨 아래 코드블록을 보면 dispatch() 를 할 때 마다,
  • getState() 를 불러서 console.log로 state를 확인했다.
  • 이 부분을 subscribe() 를 이용해서 자동화가 가능하다.

store의 subscribe(listener) 메소드는 state에 변화가 생길때마다 콜백함수(listener)를 실행시켜준다. (useEffect랑 비슷한듯)

store.subscribe(() => {
    console.log('state : ', store.getState());
})

store.dispatch(addApple());
store.dispatch(addApple());
store.dispatch(addApple());
store.dispatch(addApple());
  • 결과


(listener가 action이 끝난 '후'에 작동하는 디테일도 확인할 수 있다!)

Middleware 이용

redux.applyMiddleware() 메소드를 통해서 미들웨어를 생성할 수 있고,

redux.createStore() 의 두번째 인자로 middleware를 넣는다.

redux-logger 라는 redux middleware 모듈을 사용해보자.

npm i redux-logger

subscribe한 것을 주석처리하고 대신 logger middleware를 적용시키면

const reduxLogger = require('redux-logger');
logger = reduxLogger.createLogger();

// ...

const store = redux.createStore(
	reducer, 
	redux.applyMiddleware(logger)
);
  • 결과

state가 변할 때 마다 다음의 로그가 찍힌다.

  • action을 실행한 시각
  • prev state
  • action
  • next state

combineReducers 이용

store에 두 개 이상의 Reducer를 함께 넘기기 위해 사용한다.

// reducer1, reducer2

// ...

const rootReducer = redux.combineReducers({
	reducer1: reducer1,
	reducer2: reducer2
})

const store = redux.createStore(rootReducer);

참고

https://youtu.be/wSbjROmXTaY

https://www.notion.so/8fe54b118a06463a9112d97aab07b4b7

좋은 웹페이지 즐겨찾기