안녕하세요
미들웨어에 대한 포스팅입니다.
미들웨어를 이용하면 반복적으로 구성해야되는 로직을 쉽게 작성할 수 있습니다.
Nodejs에서 express모듈로 RestAPI서버를 만들어봤다면 쉽게 이해가 됩니다. Request가 들어오면 엔드포인트로 전달되기전에 미들웨어를 거쳤습니다.
Redux에서도 마찬가지로 Action이 Dispatch되면 Reducer로 전달되기전에 미들웨어가 실행됩니다.
이 미들웨어에서 리듀서에서 발생한 예외를 서버로 전송하는 목적으로 사용할 수도 있고, 상탯값 변경시의 로깅 등을 할 수 있습니다.
기본구조
const Middleware = store => next => action => next(action);
기본구조
const Middleware = function(store) {
return function(next) {
return function (action) {
return next(action)
}
}
}
위 코드에서처럼 중첩된 함수로 되어있어 store와 action객체를 이용한 미들웨어 처리가 가능합니다.
store의 상탯값을 호출해서 사용할 수도있고, action객체의 payload를 이용할 수도 있습니다.
import { createStore, applyMiddleware } from 'redux';
const middleware1 = store => next => action => {
console.log('middleware start1');
const result = next(action);
console.log('mideleware end1');
return result;
}
const middleware2 = store => next => action => {
console.log('middleware start2');
const result = next(action);
console.log('mideleware end2');
return result;
}
const Reducer = (state, action) => {
console.log('reducer');
return state;
}
const store = createStore(Reducer, applyMiddleware(middleware1, middleware2));
store.dispatch({type:'someAction'});
applyMiddleware
를 사용해 여러개의 미들웨어를 정의할 수 있습니다.
createStore함수의 두 번째 인자로 넣어줍니다.
middleware start1
middleware start2
reducer
middleware end1
middleware end2
만약 미들웨어를 정의하는 부분에서return next(action)
처럼 바로 리턴하지않고, next(action)
를 result변수에 담은 후 리턴했기 때문에 미들웨어가 종료된 뒤 실행할 코드를 작성할 수 있습니다.
따라서, 각 미들웨어는 reducer호출 전 후의 코드를 작성할 수 있습니다.
첫 번째 미들웨어인 middleware1은 다음 미들웨어 함수를 실행합니다. 마지막 미들웨어인 middleware2의 next함수는 store가 원래 갖고있던 dispatch메서드를 호출합니다.
immer는 불변객체를 관리하도록 도와주는 모듈입니다.
State를 불변객체로 관리하고자 할 때 Spread Syntax를 많이사용합니다.
전화번호를 수정해보겠습니다.
const obj = {
name : 'junhyuk',
info : {
address : 'a b c d e f',
phone : '010-0000-0000',
family : {
...
}
}
}
const newObj = {
...obj,
info:{
phone : '01000000000'
...obj.info,
family: {
...obj.info.family
}
}
}
중첩되는 구조가 조금만 깊어져도 복잡해집니다.
immer를 사용하면 쉽게 불변객체를 관리 할 수 있습니다.
import produce from 'immer';
const obj = {
name : 'junhyuk',
info : {
address : 'a b c d e f',
phone : '010-0000-0000',
family : {
...
}
}
}
const newObj = produce(obj, draft=>{
draft.info.phone = '01000000000'
})
function reducer(state = INITIAL_STATE, action) {
return produce (state, draft=> {
switch (action.type) {
case ADD:
draft.todos.push(action.todo);
break;
case REMOVE_ALL;
draft.todos = [];
break;
...
default:
break;
}
})
}
produce메서드가 action.type에 따라 다른 객체를 리턴합니다.
immer를 사용했기 때문에 push메서드를 사용해도 produce 메서드가 새로운 객체를 리턴합니다.