carrots-day

[ React.04.상태관리 - Redux middleware ] 본문

먹고살자/React

[ React.04.상태관리 - Redux middleware ]

당근-맨 2023. 2. 25. 12:56
728x90
반응형

Redux middleware

액션을 dispatch 했을대 reducer에서 이를 처리 하기 위해 앞서 사전이 지정된 작업들을 실행 (액션 과 리듀서 중간에 위치)


리덕스 미들웨어는 액션과 리듀서 함수 사이의 중간자 역할로, 해당 미들웨어를 통해 전달받은 액션을 제어해 취소하거나 다른 종류의 액션을 추가적으로 디스패치하는 등 효율적이고 편하게 상태 관리를 할 수 있도록 해준다. Context API 또는 MobX에서는 제공하지 않는 점에서 강점을 지닌다.

 

middleware의 필요성 💢

지금 떠오르는 생각은 그럼 왜 쓰는가이다. 사실상 리듀서상에서 어느 정도는 처리가 가능한 부분이라 생각되기 때문이다. 왜 쓰는가에 집중해보자.

  • 기본 리덕스 프로세스 : 액션 객체 생성 > 디스패치 > 리듀서 실행 > 스토어 변경
  • 미들웨어 리덕스 프로세스 : 액션 객체 생성 > 미들웨어 > 디스패치 > 리듀서 실행 > 스토어 변경

먼저 리듀서는 동기적 흐름을 제공한다. 하지만 비동기적인 요소가 필요한 경우라면 동기적 특성에 반하는 요청이된다. 예를 들어 시간을 딜레이시켜 동작하게 한다던지, 외부 데이터를 요청하고 그에 따라 다른 액션을 처리해야하는 구조라면 미들웨어를 사용하면 된다. 해당 미들웨어를 통해 state 변경에 대한 로깅을 지원한다던지, API를 호출해 중간 데이터를 제어하는 등 작업이 필요한 경우 미들웨어를 통해 해당 작업을 수행하면 된다.

 

👽 이또한 사실상 구조를 어떻게 구성하는가의 차이라고 생각한다. 만약 내가 구조를 설계한다면 다음과 같은 원칙을 적용할 것 같다.

  1. 리덕스의 리듀서는 변수에 대한 상태변경에 대한 순수함수로써 구성
  2. 공통 기능 (로깅) 미들웨어와 API 연동, 비즈니스 로직을 포함한 미들웨어 2개로 분리하여 사용

뭐 어떻게든 의도한대로 사용하면 되지 않을까.

 

middleware 동작방식

// ES6 기본 템플릿
const middleware = store => next => action => {
  // 비즈니스 로직
};

// 일반 함수 형식
const middleware = function middleware(store) {
  return function(next) {
    return function(action) {
      // 비즈니스 로직
    }
  }
}

  1. 미들웨어는 함수를 반환하는 객체다.
  2. 첫 번째 파라미터인 store는 리덕스 스토어 인스턴스로, 이 안에 dispatch, getState, subscribe 내장함수들이 들어있다.
  3. 두 번째 매개변수인 next는 액션을 다음 미들웨어에게 전달하는 함수로 store.dispatch와 비슷한 역할을 한다. next(action) 형태로 사용하며, 다음 처리해야할 미들웨어에게 액션을 넘겨주고, 최종적으로 리듀서에 액션이 전달된다. next 함수를 호출하지 않으면, 액션이 리듀서로 전달되지 않기 때문에 무시된다.
  4. action은 디스패치되어 현재 처리하고 있는 액션을 가리킨다.
  5. 미들웨어 내부에서 store.dispatch를 사용하면 첫번째 미들웨어부터 다시 처리한다.

 

middleware 종류

보편적으로 많이 사용되는 미들웨어는 이 세가지다. 오늘은 redux-logger에 대해서 다루고 다른 라이브러리는 추후 포스팅에서 다루겠다.

  • redux-logger : 액션 정보를 콘솔에 출력해주는 미들웨어
  • redux-thunk : 비동기 작업을 처리 할 때 가장 많이 사용하는 미들웨어
  • redux-saga : redux-thunk 다음으로 가장 많이 사용되는 비동기 작업 관련 미들웨어

 

middleware 구현

로깅 미들웨어는 사실 redux-logger로 구현하면 된다. 내부적으로 어떤 구조를 띄는지 이해를 위한 샘플작성을 해보자. 이전 샘플에서 확장해서 작성한다. > [ React.07.상태관리 - Redux 적용 ]

 

[ React.07.상태관리 - Redux 적용 ]

Redux 적용 기초에 대해 알아보자

velog.io


loggerMiddleware.js

로깅 미들웨어를 작성한다. 별거 없음;

// 이전상태, 액션정보, 리듀서 이후 상태를 순차적으로 콘솔에 기록하는 미들웨서
const loggerMiddleware = store => next => action => {
    console.group(action && action.type); // 액션 타입을 콘솔 그룹명으로 설정
    console.log('action : ', action);
    console.log('preState : ', store.getState()); // 리듀서 실행전 상태 로깅
    next(action); // 다음 미들웨어 혹은 리듀서에게 전달 (샘플은 미들웨어 1개뿐이기 때문에 리듀서로 액션 전달)
    console.log('state : ', store.getState());
    console.groupEnd(); // 그룹 끝
}

export default loggerMiddleware;

store.js
createStore시 미들웨어 할당

import { createStore, applyMiddleware } from 'redux';
import loggerMiddleware from './lib/loggerMiddleware';

const initialState = {
  name : 'carrots',
  age : 25
};

// reducer 선언
const reducer = (state = initialState, action) => {
  if (action.type == 'EDIT_NAME') {
    return { ...state, name : action.payload.name };
  } else if (action.type == 'EDIT_AGE') {
    return { ...state, age : action.payload.age };
  } else {
    return state;
  }
}

// createStore시 applyMiddleware 함수를 통해 Logger를 등록
const store = createStore(reducer, applyMiddleware(loggerMiddleware));

export default store; 

이후는 동일하게 작성하면 액션발생시 미들웨어가 호출되고 이전 값이 로깅된다. 이후 리듀서 실행 후 변경 값이 로깅된다. 초 간단.

 

redux-logger

사실 위에 처럼 똥꼬쇼할 필요없이 더없이 간단한 방법이 있다. redux-logger 모듈을 사용하는 것이다. 역시 사람 생각하는게 다 비슷하다.

npm install redux-logger


store.js

createStore시 redux-logger 미들웨어 할당

import { createLogger } from "redux-logger"
import { createStore, applyMiddleware } from 'redux';

// 로거 객체 생성
const logger = createLogger();
const initialState = {
  name : 'carrots',
  age : 25
};

// reducer 선언
const reducer = (state = initialState, action) => {
  if (action.type == 'EDIT_NAME') {
    return { ...state, name : action.payload.name };
  } else if (action.type == 'EDIT_AGE') {
    return { ...state, age : action.payload.age };
  } else {
    return state;
  }
}

// createStore시 applyMiddleware 함수를 통해 Logger를 등록
const store = createStore(reducer, applyMiddleware(logger));

export default store; 

끝. 뭐 어쩌라고

 

정리하며

오늘은 Redux 미들웨어에 대해 알아봣다. 의도대로 포스팅을 작성한다면 redux-toolkit에 대해 작성해야한다. 하지만 redux-toolkit은 내부적으로 redux-thunk를 지원하기 때문에 선행적으로 미들웨어에 대한 지식이 필요하다고 느껴서 해당 포스팅을 먼저 작성했다. 어차피 내껀데 뭐

 

오늘 저녁은 차돌박이이다. 🥕

 

참고 : https://1day1commit.tistory.com/134
https://velog.io/@gyumin_2/React.js-redux-middleware%EB%A6%AC%EB%8D%95%EC%8A%A4-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-redux-thunk-redux-saga
https://medium.com/@cute_mustard_sardine_17/%EB%A6%AC%EB%8D%95%EC%8A%A4-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-redux-middleware-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EA%B8%B0-4fe4ddf5d5d4
https://velog.io/@cyongchoi/Redux-MiddleWare-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0
https://itprogramming119.tistory.com/entry/react-redux-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%EC%98%88%EC%A0%9C

728x90
반응형
Comments