Front-end Developer

0%

What is Redux middleware?

Redux middleware

액션이 dispatch 되어서 리듀서에서 이를 처리하기 전에 사전에 지정된 작업들을 설정. 액션과 리듀서 사이의 중간자역할. 액션이 디스패치 된 다음, 리듀서에서 해당 액션을 받아와서 업데이트 하기 전, *추가적인 작업을 할 수 있다. 보통 비동기 작업을 처리할 때 사용한다.

추가적인 작업이란?

  • 특정 조건에 따라 액션이 무시되게 만들 수 있습니다.
  • 액션을 콘솔에 출력하거나, 서버쪽에 로깅을 할 수 있습니다.
  • 액션이 디스패치 됐을 때 이를 수정해서 리듀서에게 전달되도록 할 수 있습니다.
  • 특정 액션이 발생했을 때 이에 기반하여 다른 액션이 발생되도록 할 수 있습니다.
  • 특정 액션이 발생했을 때 특정 자바스크립트 함수를 실행시킬 수 있습니다.

함수를 연달아서 두번 리턴하는 함수.

1
2
3
const middleware = (store) => (next) => (action) => {
// 하고 싶은 작업...
};
1
2
3
4
5
6
7
8
9
10
11
12
function middleware(store) {
//store: 리덕스 스토어의 인스턴스, dispatch, getState, subscribe 내장함수들이 들어있다.
return function (next) {
// next: next(action)의 형태로 액션을 다음 미들웨어에게 전달.
// 다음 미들웨어가 없다면 리듀서에게 전달한다.
//next를 호출하지 않으면 액션이 무시처리되어 리듀서에게 전달안됨.
return function (action) {
//action: 현재 처리하고 있는 액션 객체
// 하고 싶은 작업...
};
};
}

리덕스 스토어에 여러 개의 미들웨어 등록 가능 새로운 액션이 디스패치되면 첫 번째 등록한 미들웨어가 호출되고, next(action)을 호출하면 다음 미들웨어로 액션이 넘어간다. 미들웨어에서 store.dispatch를 사용하면 다른 액션을 추가로 발생시킬 수 있다.

redux-thunk

redux-thunk를 사용하여 동기화된 액션을 네트워크 요청과 함께 사용할 수 있다. 이를 통해 action creator는 액션 객체 대신 함수를 반환할 수 있다. 이를 통해 action creator가 thunk가 되는 것이다. action creator가 함수를 반환하면 thunk middleware에 읳해 실행되는데, 이는 순수할 필요가 없다. 비동기 api 호출과 같은 사이드 이펙트가 허용되고, 동기적인 action을 보낸다.

객체 대신 함수를 생성하는 액션 생성함수를 작성. 미들웨어 안에서는 액션 값을 객체가 아닌 함수로 받아오게 하여 액션이 함수타입이면 실행시키게 만들 수 있다. 즉, 액션 객체가 아닌 함수를 디스패치 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
const thunk = (store) => (next) => (action) =>
typeof action === "function"
? action(store.dispatch, store.getState)
: next(action);

//dispatch할 때
const myThunk = () => (dispatch, getState) => {
dispatch({ type: "HELLO" });
dispatch({ type: "BYE" });
};

dispatch(myThunk());

미들웨어를 사용하면 함수를 디스패치 할 수 있는데, 이때 dispatch와 getState를 파라미터로 받아와야 한다. 이 함수를 만들어주는 함수를 thunk라 부른다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const getComments = () => (dispatch, getState) => {
// 액션을 dispatch할 수 있고,
// getState를 사용하여 현재 상태를 조회할 수 있다.
const id = getState().post.activeId;

// 요청이 시작했음을 알리는 액션
dispatch({type: 'GET_COMMENTS});

// 댓글을 조회하는 프로미스를 반환하는 getCommets가 있다고 가정했을 때
api
.getComments(id) //요청
.then(comments => dispatch({type:'GET_COMMENTS_SUCCESS', id, comments}))
//성공시
.catch(e => dispatch({type:'GET_COMMENTS_ERROR',error: e})); //실패시
};
1
2
3
4
5
6
7
8
9
10
11
//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 });
}
};

프로미스를 다룰 때 고려해야 할 사항

  • 프로미스가 시작, 성공, 실패했을때 다른 액션을 디스패치해야합니다.
  • 각 프로미스마다 thunk 함수를 만들어주어야 합니다.
  • 리듀서에서 액션에 따라 로딩중, 결과, 에러 상태를 변경해주어야 합니다.

References
모던리액트