18-1. 미들웨어란?
리덕스 미들웨어는 액션을 디스패치했을 때 리듀서가 액션을 처리하기 전에 미리 정해둔 작업들을 실행한다
여기에서 작업은 액션 값에 따라서 여러가지 행동을 할 수 있는데 발생하는 액션을 취소하거나, 다른 액션을 발생시키거나 하는 작업들이 가능하다
(대충 액션 → 미들웨어 → 리듀서 → 스토어)그림
18-1-1. 미들웨어 만들기
const loggerMiddleware = store => next => action =>{};
또는
const loggerMiddleware = function loggerMiddleware(store){
return function(next) {
return function(action){
//
};
};
};
이처럼 함수 3개가 중첩되어있는 모양이 미들웨어의 기본 골자이다
store는 리덕스 스토어의 인스턴스를 가르킨다
acitons는 디스패치된 액션을 가르킨다
next는 함수의 형태로 존재하며 store.dispatch와 비슷하게 액션을 객체를 파라미터로 받는다
⇒ next(action)이 호출된다면 다음 미들웨어로 넘겨주고, 더이상 넘겨 줄 미들웨어가 없다면 리듀서에게 액션을 넘겨준다
const loggerMiddleware = function (store){
return function (next){
return function (action){
console.group(action && action.type);
console.log('이전 상태', store.getState());
console.log('액션', action);
next(action);
console.log('다음 상태',store.getState());
console.groupEnd();
}
}
}
위를 바탕으로 만든 발생한 액션의 정보, 디스패치되기 전,후의 상태값을 로깅하는 미들웨어를 작성한 코드이다
위의 내용으로는 이해가 잘 되지 않아 따로 공부한 내용
18-2. 비동기 작업을 처리하는 미들웨어 사용
- redux-thunk : 비동기 작업을 처리할 때 가장 많이 사용하는 미들웨어로 객체가 아닌 함수 형태의 액션을 디스패치할 수 있게 해준다
- redux-saga : 특정 액션이 디스패치되었을 때 정해진 로직에 따라 다른 액션을 디스패치시킬 수 있게 해준다
18-2-1. redux-thunk
Thunk는 특정 작업을 나중에 할 수 있도록 미루기 위해 함수 형태로 감싼 것을 의미한다
18-2-2. Thunk 생성 함수 만들기
아래는 1초 뒤에 counter의 값을 증가, 감소 시키는 Thunk를 생성하는 함수다
export const increaseAsync = ()=>dispatch =>{
setTimeout(()=>{
dispatch(increase());
},1000);
}
export const decreaseAsync = ()=>dispatch =>{
setTimeout(()=>{
dispatch(decrease());
},1000);
}
어떻게 사용하지?하고 생각했는데 액션을 발생시키는 것과 똑같이 dispatch에 넣어주면 되었다
const CounterContainer = () => {
const number = useSelector(state=>state.counter);
const dispatch = useDispatch();
const onIncrease = useCallback(()=>dispatch(increaseAsync()),[dispatch]);
const onDecrease = useCallback(()=>dispatch(decreaseAsync()),[dispatch]);
...
}
dispatch에 액션이 아닌 Thunk 발생 함수를 넣어 주었고 Thunk 안에는 증가와 감소 액션을 파라미터로 갖는 dispatch가 들어있다
그래서 첫 번째 dispatch는 액션이 아닌 함수가, 두 번째 dispatch에는 그 함수 안에 들어있는 actiton이 실행됨을 알 수 있다
18-2-3. 웹 요청 비동기 작업 처리
전체코드는 여기
헷갈리는 부분만 기록한 것
thunk 생성 함수
thunk 함수 내부에서는 요청을 시작했을 때, 성공적으로 끝났을 때, 실패했을 때 각각 다른 dispatch를 실행시킨다
export const getPost = id => async dispatch =>{
// 요청 시작을 알림
dispatch({type:GET_POST});
try{
const response = await api.getPost(id);
// 성공했을 때의 dispatch
dispatch({
type:GET_POST_SUCCESS,
payload : response.data,
});
}
// 실패했을 때의 error핸들링
catch (e){
// 실패했을 때의 dispatch
dispatch({
type:GET_POST_FAILURE,
payload : e,
error : true,
});
throw e;
}
};
State
sample의 state는 이렇게 구성되어있다
const initialState = {
loading : {
GET_POST : false,
GET_USERS : false,
},
post: null,
users: null,
};
loading 객체에서는 현재 요청 중인 상태를 나타내고 post와 users에서는 api 요청 후에 받아온 데이터 값을 넣어두는 변수다
reducer
export default function reducer(state = initialState, action){
switch (action.type){
case GET_POST :
return ({...state, loading: {...state.loading, GET_POST : true}});
case GET_POST_SUCCESS :
return ({...state, loading: {...state.loading, GET_POST: false}, post : action.payload});
case GET_POST_FAILURE :
return ({...state, loading: {...state.loading, GET_POST: false}});
case GET_USER :
return ({...state, loading: {...state.loading, GET_USERS: true}});
case GET_USER_SUCCESS :
return ({...state, loading: {...state.loading, GET_USERS: false}, users : action.payload});
case GET_USER_FAILURE :
return ({...state, loading: {...state.loading, GET_USERS: false}});
default : return state;
}
};
특별할 것 없는 액션에 따라서 상태를 업데이트 시켜주는 reducer다
'React > 리액트를 다루는 기술' 카테고리의 다른 글
19. 코드 스플리팅 (0) | 2021.02.22 |
---|---|
21. 백엔드 프로그래밍 : Node.js-Koa (0) | 2021.02.21 |
17. 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (0) | 2021.02.12 |
16. 리덕스 라이브러리 이해하기 (0) | 2021.02.11 |
15. Context API (0) | 2021.02.10 |