리덕스 미들웨어
dispatch, getState, subscribe 등의 내장함수 포함next(action)next 를 호출하지 않게 된다면 액션이 무시처리되어 리듀서에게로 전달되지 않는다const middleware = store => next => action => {
// 하고 싶은 작업...
}
function middleware(store) {
return function (next) {
return function (action) {
// 하고 싶은 작업...
};
};
};

next(action)을 호출하게 되면 다음 미들웨어로 액션이 넘어감store.dispatch 를 사용하면 다른 액션을 추가적으로 발생시킬 수도 있다미들웨어 생성
// middlewares/myLogger.js
// 단순히 전달받은 액션을 출력하고 다음으로 넘기는 작업
const myLogger = store => next => action => {
console.log(action);
const result = next(action);
console.log('\t', store.getState()); // 액션이 리듀서까지 전달되고 난 후의 새로운 상태 확인
return result;
};
export default myLogger;
미들웨어 적용
// index.js
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import myLogger from './middlewares/myLogger';
const store = createStore(rootReducer, applyMiddleware(myLogger));
리덕스 관련 값들을 콘솔에 로깅하는건 이렇게 직접 만드는 것 보단
redux-logger 라는 미들웨어를 사용하는게 더욱 좋다
yarn add redux-logger
여러 개의 미들웨어를 등록할 수 있다
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import myLogger from './middlewares/myLogger'; // 만든 미들웨어
import logger from 'redux-logger'; // 라이브러리
const store = createStore(rootReducer, applyMiddleware(myLogger, logger)); // 여러개의 미들웨어를 적용 할 수 있습니다.
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
Redux DevTools
Redux DevTools를 미들웨어와 함께 사용해야 하는 방법
// index.js
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(logger))
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
dispatch 와 getState 를 파라미터로 받아와주어야 한다
// dispatch를 비동기로 실행하고 싶을 때 사용
const getComments = () => async (dispatch, getState) => {
const id = getState().post.activeId;
dispatch({ type: 'GET_COMMENTS' });
try {
const comments = await api.getComments(id);
dispatch({ type: 'GET_COMMENTS_SUCCESS', id, comments });
} catch (e) {
dispatch({ type: 'GET_COMMENTS_ERROR', error: e });
}
}
사용법
yarn add redux-thunk
// index.js
import ReduxThunk from 'redux-thunk';
const store = createStore(
rootReducer,
// logger 를 사용하는 경우, logger가 가장 마지막에 와야한다
composeWithDevTools(applyMiddleware(ReduxThunk, logger))
);
// modules/counter.js
// 액션 타입
const INCREASE = 'INCREASE';
const DECREASE = 'DECREASE';
// 액션 생성 함수
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
// 함수인 액션 - getState를 쓰지 않는다면 굳이 파라미터로 받아올 필요 없습니다.
export const increaseAsync = () => dispatch => {
setTimeout(() => dispatch(increase()), 1000);
};
export const decreaseAsync = () => dispatch => {
setTimeout(() => dispatch(decrease()), 1000);
};
// 초깃값 (상태가 객체가 아니라 그냥 숫자여도 상관 없습니다.)
const initialState = 0;
export default function counter(state = initialState, action) {
switch (action.type) {
case INCREASE:
return state + 1;
case DECREASE:
return state - 1;
default:
return state;
}
}
// containers/CounterContainer.js
import React from 'react';
import Counter from '../components/Counter';
import { useSelector, useDispatch } from 'react-redux';
import { increaseAsync, decreaseAsync } from '../modules/counter';
function CounterContainer() {
const number = useSelector(state => state.counter);
const dispatch = useDispatch();
const onIncrease = () => {
dispatch(increaseAsync());
};
const onDecrease = () => {
dispatch(decreaseAsync());
};
// 기존 코드
const onIncrease = () => {
dispatch(increase());
};
const onDecrease = () => {
dispatch(decrease());
};
return (
<Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
);
}
export default CounterContainer;