1. Middleware 란?
미들웨어는
“프레임워크의 요청과 응답 사이에 추가할 수 있는 코드” 라고 생각할 수 있다.
일반적으로 express, koa와 같은 서버 프레임워크단에서 미들웨어란 개념을 많이 사용하는데 흔히 미들웨어에서 CORS 관련 설정, 로깅 등의 목적으로 활용한다고 한다.
미들웨어의 가장 큰 특징은
“연결" 할 수 있다는 점이다.
각각의 미들웨어는 서로 독립적이며, 프레임워크 안에 여러개의 미들웨어를 추가해서 연결할 수 있다. 이로 인해 개발자는 미들웨어를 기반으로 일련의 흐름을 작성하듯이 프로그램을 설계할 수 있게 된다. 이런 특징으로 인해 JavaScript를 이용한 서버 프레임워크 중 가장 유명한 express 같은 경우에는 기본적인 핵심 기능만 포함하고 있으며 그 외의 코드들은 모두 express에 middleware를 추가하는 방식으로 설계를 한다고 한다.
서버단의 미들웨어와 다른점은
서버의 미들웨어는 요청과 응답 사이에서 동작하지만 리덕스의 미들웨어는 액션이 디스패칭되어서 reducer에 전달되는 과정 사이에서 동작한다는 점이다.
2. 깊이 있게 보는 Middleware
해당 내용은 이해가 어렵고 내용이 길고 공부가 더 필요해 따로 다시 정리하였다.
3. Middleware 를 사용하는 이유
리덕스를 사용하면서 미들웨어를 사용하는 이유는 크게 두 가지로 나눠볼 수 있다.
- 횡단 관심사를 처리하기 위해
- 관심사의 분리를 실현하기 위해
1) 횡단 관심사를 처리하기 위해
횡단 관심사란 애플리케이션의 여러 서비스에 걸쳐서 공통적으로 실행되어야 하는 코드를 의미한다. 이러한 코드들을 매번 필요한 곳에 작성하면서 중복을 발생시키는 것이 아니라, 미들웨어를 통해서 리덕스의 중간 과정에서 모두 처리하게 된다면 훨씬 깔끔하고 좋은 설계를 가진 애플리케이션으로 만들 수 있다.
2) 관심사의 분리를 실현하기 위해
프론트엔드 애플리케이션을 개발하면서 API 호출 등의 사이드 이펙트를 완전히 배제할 순 없고, 특정 순간에는 반드시 이러한 사이드 이펙트를 수행해야하는 순간이 발생한다. API 호출 등의 비동기 처리를 동반한 사이드 이펙트 뿐만 아니라 동기적인 코드일지라도 상태값을 수정하기 위해서 복잡한 로직이 수행되어야 하는 경우도 존재한다.
리덕스를 사용하면서 이런 동작들은 어디서 수행해줘야 할까?
관심사의 분리와 응집도 측면에서 봤을때, 상태값을 수정하는 것에 연관된 동작이기에 상태를 가지고 있는 리덕스 내에서 처리하는 것이 올바른 접근법으로 보입니다. 하지만 리덕스의 모든 과정은 순수하게 이루어진다. 순수하게 이루어진다는 의미는 사이드 이펙트를 수행할 공간이 없다는 것이다.
리덕스는 순수한 객체인 액션을 디스패치를 통해서 전달하고 순수함수인 리듀서에서 이를 처리해서 새로운 상태값을 만드는 흐름을 따른다. 이 과정 중간에 사이드 이펙트나, 복잡한 로직을 처리하기에 적절한 공간은 존재하지 않는다.
이러한 동작을 수행하기 위한 가장 단순한 방법은 리액트 컴포넌트 안에서 사이드 이펙트를 모두 다 수행한 뒤, 그 결과를 통해서 액션을 만들고 디스패치 하는 것이다.
- 위와 같은 방법으로 코드를 작성해도 해도 실제 동작상에는 아무런 차이가 없다.
- 하지만, 리덕스 스토어의 상태를 다루기 위한 관심사가 컴포넌트와 리덕스 두가지 공간으로 분리되서 작성된다는 점
- 컴포넌트에서 다루는 관심사가 데이터를 UI로 표출하는 것뿐만 아니라 상태값을 변경하는 것도 다루게 된다는 점
등 으로 인해 관심사의 분리가 제대로 되지 않는 방식이라는 한계가 있다.
🛠 이러한 문제를 해결하기 위해서, 리덕스의 미들웨어를 활용할 수 있다.
4. Implement Middleware
간단한 형태의 Middleware를 만들면서 미들웨어를 활용해보기
아래의 동작 과정을 이행하는 함수를 만들어 미들웨어를 만들기
- store를 인자로 받아서 next 를 인자로 받는 또다른 함수를 리턴한다.
- next를 인자로 받아서, action을 인자로 받는 또다른 함수를 리턴한다.
- action을 인자로 받아서, 원하는 동작을 수행한 후 next에 action을 인자로 호출하여 다음 미들웨어로 전달하는 함수를 리턴한다.
이 과정을 거쳐서 로그를 기록하는 미들웨어를 만들면 아래와 같다.
const logger = (store) => (next) => (action) => {
console.group(action.type);
console.log("dispatching", action);
next(action);
console.log("next state", store.getState());
console.groupEnd();
};
다음으로 사이드 이펙트를 미들웨어단에서 수행하기 위한 방법을 고민해보기
기존에 알고 이해해야 하는 정보
- 리덕스에서 리듀서에 전달되는 액션은 반드시 단순한 형태의 객체여야 한다.
- 하지만, 미들웨어가 받는 액션은 반드시 객체일 필요는 없다.
- 미들웨어에서 next 를 호출하지 않으면 해당 액션은 다음 미들웨어로 전달되지 않는다. 즉, 특정 미들웨어에서 액션이 리듀서로 전달되지 않게 취소해버릴수도 있다는 의미입니다.
- 미들웨어에는 store객체를 인자로 받았기에 이에 접근할 수 있다. 즉, store.dispatch 를 직접 호출할수도 있다는 의미입니다. 리덕스 내부에서는 미들웨어에서 store.dispatch 를 호출했을 경우 해당 액션을 가장 처음 미들웨어부터 다시 실행해주는 동작을 수행.
- (이 페이지에서 구현한 applyMiddelware의 경우에는 이 동작을 수행해주지 않지만, 실제 리덕스에서 제공해주는 applyMiddleware 함수에서는 위와 같은 동작을 수행.)
위의 정보들을 종합하면, action으로 우리가 원하는 동작을 수행하는 함수를 전달한 뒤, 미들웨어에서 해당 함수를 호출하고 그 결과값을 다시 store.dispatch 를 통해서 전달하는 방법을 사용할 수 있습니다.
이러한 동작을 수행하는 미들웨어가 바로 redux-thunk 이다. thunk의 경우 npm에서 인스톨해서 사용할수도 있지만, 간단하기에 직접 만들수도 있다.
const thunk = (store) => (next) => (action) => {
if (typeof action === "function") {
action(store.dispatch, store.getState);
} else {
next(action);
}
};
// use thunk
const fetchSomeData = (dispatch, getState) => {
client.get('todos').then(todos => {
dispatch({ type: 'todos/loadTodos', payload: todos })
})
};
function Component() {
useEffect(() => dispatch(fetchSomeData), [fetchSomeData]);
}
5. Redux DevTools
- Redux의 설계는 예측가능성을 가장 큰 중점으로 두고 설계했으며 그로 인해 애플리케이션의 동작을 분석하고, 예측하는 디버깅을 수행하기 용이하다.
- 이런 특성을 인해 디버깅 기능을 잘 활용할 수 있는 Redux DevTools란 개발자 도구가 존재한다.
- 브라우저의 익스텐션을 통해 리덕스의 동작을 분석하고, 추가적인 동작을 수행하도록 할 수 있다.
- 이를 사용하기 위해서는 브라우저에서 익스텐션을 설치하고, 코드에서 DevTools 사용 설정을 해줘야 한다.
- 코드에서 편리하게 사용 설정을 하기 위해서는 @redux-devtools/extension 라이브러리를 활용할 수 있다.
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from '@redux-devtools/extension';
const store = createStore(
reducer,
composeWithDevTools(
applyMiddleware(...middleware)
// other store enhancers if any
)
);
- 참고자료
'Library & Framework > Redux' 카테고리의 다른 글
Redux MiddleWare 깊이 있게 살펴보자! (0) | 2022.10.31 |
---|---|
Redux-Saga (0) | 2022.10.29 |
Redux (0) | 2022.10.29 |