리덕스 창시자인 댄 아브라모프가 만든 가장 많이 사용되는 비동기 작업 미들웨어다. 이 미들웨어를 사용하면 액션 객체가 아닌 함수를 디스패치 할 수 있다
리덕스에서 미들웨어는 주로 비동기 작업을 처리 할 때 사용한다.
리듀서에서 발생한 예외를 서버로 전송하는 등의 목적으로 미들웨어를 활용할 수 있다.
미들웨어는 리듀서가 액션을 처리하기 전에 실행되는 함수로 액션과 리듀서 사이의 중간자라고 볼 수 있다.
리덕스 미들웨어 라이브러리 redux-thunk, redux-saga, redux-observable, redux-promise-middleware등을 서치하여 사용할 수 있고, 만들어서 사용할 수도 있다.
실제 프로젝트를 작업 할 때에는, 미들웨어를 직접 만들어서 사용하는 경우는 그렇게 많지 않다. 하지만 미들웨어가 어떻게 작동하는지 이해를 하려면 직접 만들어봐야한다.
먼저 디렉토리에 seongMiddleware.js 파일을 생성하기
📔 seongMiddleware 만들기: 기본 구조
const seongMiddleware = store => next => action => next(action);
export default seongMiddleware;
미들웨어는 함수 세 개가 중첩된 구조이다.
📔 seongMiddleware 만들기: 화살표 함수를 사용하지 않은 미들웨어 코드
const seongMiddleware = function(store) {
return function(next) {
return function(action) {
return next(action);
};
};
};
export default seongMiddleware;
미들웨어는 스토어와 액션 객체를 기반으로 필요한 작업을 수행할 수 있다. next 함수를 호출하면 다른 미들웨어 함수가 호출되면서 최종적으로 리듀서 함수가 호출된다.
const seongMiddleware = store => next => action => {
console.log('현재 상태', store.getState()); // 현재 스토어 상태값 기록
console.log('액션', action); // 액션 기록
const result = next(action); // 액션을 다음 미들웨어, 혹은 리듀서로 넘김
console.log('다음 상태', store.getState()); // 액션 처리 후의 스토어 상태 기록
console.log('\n'); // 기록 구분을 위한 비어있는 줄 프린트
return result; // 여기서 반환하는 값은 store.dispatch(ACTION_TYPE) 했을때의 결과로 설정
}
export default seongMiddleware; // 불러와서 사용 할 수 있도록 내보내줌
$ npm install redux-thunk
createStore(rootReducer, applyMiddleware(thunk));
// store.js 파일 생성하기
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
// index.jsx 파일에서 스토어 가져다 쓰도록 만들어주기
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
(
<Provider store={store}>
<App />
</Provider>
),
document.getElementById('root'),
);
이제부터 React 애플리케이션 내에서 비동기 작업 생성자를 만들 수 있다.
우선 Redux Thunk를 사용한다는 것은 비동기 액션을 만드는 것이다. 비동기에 대한 이해가 필요하고, 대표적인 비동기 함수 fetch에 대해 알고 있어야 한다.
⭐ 실제 적용을 위해 비동기 액션을 만들어 보도록 하자.
// App 컴포넌트
import { useDispatch, useSelector } from 'react-redux';
import { loadUserData } from './actions';
const dispatch = useDispatch(); // dispatch를 사용하기 위한 준비
const { name, age } = useSelector((state) => ({
name: state.name,
age: state.name, // store에 접근하여 state 가져오기
}));
function handleClick() {
dispatch(loadUserData()); // store에 있는 state 바꾸는 함수 실행
};
export default function App() {
return (
<div>
<p>이름: {name}</p>
<p>나이: {age}</p>
<button onClick={() => handleClick()}>확인</button>
</div>
);
};
// actions.js
import {
fetchUserData, // API요청 함수
} from './services/api';
export function loadUserData() {
return async (dispatch) => {
const userData = await fetchUserData();
dispatch(setUserData(userData));
};
}
useDispatch, useSelector 훅을 이용해서 내가 사용하고자는 API정보를 사용할 수 있다.
- 참고문서: 실전 리액트 프로그래밍 [이재승 지음, 인사이트]
- 참고사이트: https://react.vlpt.us/redux-middleware/04-redux-thunk.html