본문으로 바로가기

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가 들어있다

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d5a01e8b-1065-4d67-83d5-3c4297226295/Untitled.png

그래서 첫 번째 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다