벨로퍼트 리액트 - 7. 리덕스 미들웨어
7-3. redux-logger 사용 및 미들웨어와 함께 DevTools 함께 사용하기
1) redux-logger 사용하기
redux-logger 설치
$ npm add redux-logger
리덕스 미들웨어는 여러개를 등록할 수 있다. ⇒ index.js에 적용
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import myLogger from './middlewares/myLogger';
import logger from 'redux-logger';
const root = ReactDOM.createRoot(document.getElementById('root'));
const store = createStore(rootReducer, applyMiddleware(myLogger, logger));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
myLogger 비활성화.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import logger from 'redux-logger';
const root = ReactDOM.createRoot(document.getElementById('root'));
const store = createStore(rootReducer, applyMiddleware(logger));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
2) Redux DevTools 사용하기
기본 사용 예시
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
const store = createStore(reducer, composeWithDevTools(
applyMiddleware(...middleware),
// other store enhancers if any
));
redux-devtools-extension 설치
$ npm add redux-devtools-extension
index.js 수정
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import logger from 'redux-logger';
import { composeWithDevTools } from 'redux-devtools-extension';
const root = ReactDOM.createRoot(document.getElementById('root'));
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(logger))
// 여러개의 미들웨어 적용 가능
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
7-4. redux-thunk
1) 소개
redux-thunk : 리덕스에서 비동기 작업을 처리 할때 가장 많이 사용하는 미들웨어.
액션 객체가 아닌 함수를 디스패치 할 수 있다.
함수를 디스패치 할때는 해당 함수에서 dispatch와 getState를 파라미터로 받아와야한다. 이 함수를 만들어주는 함수가 thunk이다.
thunk 의 사용 예시 1
const getComments = () => (dispatch, getState) => {
// 이 안에서는 액션을 dispatch 할 수도 있고
// getState를 사용하여 현재 상태도 조회 할 수 있습니다.
const id = getState().post.activeId;
// 요청이 시작했음을 알리는 액션
dispatch({ type: 'GET_COMMENTS' });
// 댓글을 조회하는 프로미스를 반환하는 getComments 가 있다고 가정해봅시다.
api
.getComments(id) // 요청을 하고
.then(comments => dispatch({ type: 'GET_COMMENTS_SUCCESS', id, comments })) // 성공시
.catch(e => dispatch({ type: 'GET_COMMENTS_ERROR', error: e })); // 실패시
};
thunk에서 async/await를 사용하는 예시
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 });
}
}
2) redux-thunk 설치 및 적용하기
$ npm add redux-thunk
redux-thunk를 index.js에서 불러와서 applyMiddlewares를 적용
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import logger from 'redux-logger';
import { composeWithDevTools } from 'redux-devtools-extension';
import ReduxThunk from 'redux-thunk';
const root = ReactDOM.createRoot(document.getElementById('root'));
const store = createStore(
rootReducer,
// logger를 사용하는 경우 logger가 맨 마지막에 위치해야함
composeWithDevTools(applyMiddleware(ReduxThunk, logger))
// 여러개의 미들웨어 적용 가능
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
3) 카운터 딜레이하기
thunk 함수를 만들고 setTimeout을 사용해서 액션이 디스패치되는 것을 1초씩 딜레이시키는 예제
modules/counter.js
// 액션 타입
const INCREASE = 'INCREASE';
const DECREASE = 'DECREASE';
// 액션 생성 함수
export const increase = () => ({type: INCREASE});
export const decrease = () => ({type: DECREASE});
// getState를 쓰지 않는다면 굳이 파리미터로 받아올 필요 X
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;
}
}
container/CounterContainer.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import Counter from "../components/Counter";
import { decreaseAsync, increaseAsync } from "../modules/counter";
function CounterContainer() {
const number = useSelector(state => state.counter);
const dispatch = useDispatch();
const onIncrease = () => {
dispatch(increaseAsync());
};
const onDecrease = () => {
dispatch(decreaseAsync());
};
return (
<Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
);
}
export default CounterContainer;