-
[Redux] Redux-thunkFront-End(Web)/React - 라이브러리들 2021. 2. 18. 15:40반응형
🤔 Redux 의 비동기 오류
Context API 에서 Redux 로 수정하는 토이 프로젝트를 진행하는 중이었다.
action 생성자들을 별도파일로 제작하여 import 해서 사용중이었고, 이처럼 fetch() 로 가져온 데이터로 상태를 최신화할때 에러가 생겼다.
내용은 대충, fetchList() 라는 액션 생성자에 cartList를 담았는데 이것이 객체형태로 정상적인 반환이 되지 않은 것 같다.
또한, 대놓고 Async action에 대한 미들웨어를 사용하라고 권장하고 있다.
이러한, 비동기 처리를 위한 적절한 미들웨어를 찾아보았다.
💜 Redux-thunk 알아가기
리덕스를 사용하는 앱에서 비동기 작업을 사용할 때, 가장 기본적인 방법으로 사용되는 것이 redux-thunk 이다.
이 미들웨어는, 리덕스를 개발한 Dan Abramov 에 의해 만들어졌으며, 공식문서도 이 미들웨어를 통한 비동기 처리를 권장한다.
Redux-thunk 의 장점은 직관적이고 익숙한 비동기 작업이 가능하다는 것이다.
- thunk 란?
?????? 과연 Redux 와 '푹, 탁' 의 연결고리는 무엇일까 ㅋㅋㅋㅋㅋㅋㅋ
thunk는 특정 작업을 나중에 하도록 미루기 위해 함수형태로 감쌌다는 의미이다. (출처:ko.wikipedia.org/wiki/%EC%8D%BD%ED%81%AC)
const sumNow = 1 + 2; const sumSync = () => 1 + 2; // sumSync()
이처럼, sumNow는 바로 덧셈을 진행하지만, sumSync() 함수는 호출되기 전까지 덧셈을 진행하지 않는다.
객체가 아닌 함수를 반환하는 액션 생성자를 만들 수 있는 Redux-thunk 의 기능에 아주 어울리는 단어이지 않나 싶다.
- Redux-thunk 의 역할
위에서 얘기했듯, Redux-thunk 는 액션 생성자가 객체 대신 함수를 반환할 수 있도록 해주는 미들웨어이다.
일반 액션 생성자는 아래처럼 받은 변수를 활용해서, 액션 객체를 반환하는 역할을 한다.
const actionCreator = (payload) => ({action: 'ACTION', payload});
이러한 객체 대신 함수를 반환하는 이유는, 특정 액션을 딜레이 시키거나 조건부로 취소하는 등에 있다.
// 디스패치를 지연시키는 경우 function incrementAsync(sec, gap) { return function(dispatch) { setTimeout(() => { dispatch(increment(gap)); }, 1000); } } // 디스패치를 상태 조건부로 실행하는 경우 function incrementIfOdd() { return (dispatch, getState) => { const { counter } = getState(); if (counter % 2 === 0) { return; } dispatch(increment()); }; }
* 액션 생성자 인자로 사용된 함수의 인자에 dispatch, getState를 전달하면, 스토어의 상태를 참조해서 디스패치가 가능한 것
💜 Redux-thunk 사용하기
- 설치
npm install redux-thunk
- 적용
이전 포스팅의, 미들웨어나 redux-logger 적용방법과 똑같다. Store를 설정할 때, applyMiddleware() 를 사용한다.
import { createStore, applyMiddleware } from 'redux'; import ReduxThunk from 'redux-thunk'; // default 모듈을 받아온다. import reducer from './reducer'; const store = createStore(reducer, applyMiddleware(ReduxThunk)) export default store;
* 기본 템플릿
const thunkActionCreator = (payload) => (dispatch, getState) => { // Code }
다음과 같이, 액션 생성자를 만드는데 내부 인자로는 함수가 적용된다.
- Redux-thunk 반영 (Redux-Cart)
// store.js import { applyMiddleware, createStore } from 'redux'; import ReduxThunk from 'redux-thunk'; import RootReducer from './Reducer'; const store = createStore( RootReducer, applyMiddleware(ReduxThunk), ); // app.js const fetchData = async () => { dispatch(loadStart()); try { const res = await fetch(DATA_API); const cartList = await res.json(); await dispatch(fetchList(cartList)); // 디스패치에 함수 적용 dispatch(loadEnd()); } catch(err) { alert(err); } }
store.js 에서 applyMiddleware 를 통해 redux-thunk 를 반영한 모습이다.
fetchData() 는 패치함수이면서, 동시에 액션 생성자가 된다. 또, thunk 덕에 하나의 생성자에서 다중 디스패치가 가능하다.
이처럼, 인자로 함수를 받기 때문에 Async Function 를 적용했을 뿐 아니라, 내부에 try - catch 로직도 반영했다.
- 단점
Redux-thunk 는 보시다시피, 액션 생성자에 함수를 적용할 수 있다는 특징이 있다. 하지만, 이것이 한편으론 단점이 될 수 있다.
- 로직의 일관성이 없어진다. 액션 생성자가 어떤 경우에는 액션 객체를, 어떤 경우에는 API 요청이나 비동기를 처리하게 된다.
- 액션 생성자의 로직이 복잡해진다. 생성자는 액션 객체를 반환해서 디스패치로 전달하는 역할에 충실해야 하는데 부가로직이 붙는 것이다.
redux-thunk를 통해, 쇼핑카트의 서버를 패치하는 Async Function 을 액션 생성자에 활용할 수 있었다.
Redux 비동기, redux-thunk 를 공부하면 항상 단짝저럼 붙는 미들웨어가 있는데, 이것이 바로 redux-saga 이다.
다음 포스팅에선 redux-saga에 대해 공부하고, 둘 중 더 적합한? 혹은 효율적인 미들웨어를 프로젝트 비동기 처리에 적용고자한다.
[출처]
- 이소영 님의 미디엄: medium.com/humanscape-tech/redux%EC%99%80-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-thunk-saga-43bb012503e4
- 벨로퍼트 님의 블로그: react.vlpt.us/redux-middleware/04-redux-thunk.html , velopert.com/3401
- a-tothe-z 님의 블로그: a-tothe-z.tistory.com/14
반응형'Front-End(Web) > React - 라이브러리들' 카테고리의 다른 글
[Recoil] 전역 상태관리 라이브러리 - Recoil 정복기 (0) 2021.12.30 [Redux] Redux-Saga (1) 2021.02.21 [Redux] 미들웨어(Middleware) (0) 2021.02.18 [Redux] Hooks - useSelector, useDispatch (0) 2021.02.17 [Redux] React-Redux (0) 2021.02.16