리덕스라고 비동기적인 작업을 벗어날 수 있는 것은 아니겠죠. 아마도 여러 방법이 있겠지만 오늘 제가 배운 것은 Redux Thunk 라는 미들웨어를 사용하는 방식입니다.
Redux Thunk 는 놀랍게도 14줄의 소스코드로 구성되어 있습니다. "14줄 밖에 안되니까 쉽겠지?" 라는 마인드로 접근했지만 소스코드만으로 이해할 만한 레벨이 아직 아니라는 깨달음을 얻었네요.
우선 소스코드를 읽는데 도움을 얻을 수 있는 공식 문서를 먼저 탐구해보도록 하겠습니다.
앞부분에는 Redux Thunk 를 어떻게 설치하고 사용할 수 있는지가 나와있고, "Why Do I Need This?" 파트에서 왜 Redux Thunk 가 필요한지에 대해 설명하고 있네요.
리덕스 store 자체만으로는
action
을dispatch
하는 작업을 통한 간단한 동기적 업데이트만 할 수 있습니다. 미들웨어는 store 의 기능을 확장시키고, store 와 상호작용하는 비동기적 로직을 작성할 수 있게 합니다.Thunk 는 리덕스의 사이드 이펙트 로직을 위해 추천되는 미들웨어이며, store 에 접근해야 하는 복잡한 동기적 로직이나 AJAX requests 와 같은 간단한 비동기적 로직을 작성할 수 있습니다.
Redux Thunk 를 사용하면 action
대신 함수를 리턴하는 action creators 를 작성할 수 있습니다. 이를 통해서 action
의 dispatch
를 딜레이 시키거나, 특정한 상황에서만 dispatch
하도록 할 수 있죠.
공식 문서의 Motivation 부분에서 함수를 리턴하는 action creator 를 어떻게 작성할 수 있는지를 코드로 보여주고 있습니다.
const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
function increment() {
return {
type: INCREMENT_COUNTER,
};
}
function incrementAsync() {
return (dispatch) => {
setTimeout(() => {
// Yay! Can invoke sync or async actions with `dispatch`
dispatch(increment());
}, 1000);
};
}
위의 코드는 비동기적인 dispatch
작업을 실행하는 함수를 리턴하는 action creator 입니다. increment() 함수를 통해서는 action
을 생성하도록 되어있구요. incrementAsync() 함수를 통해 1초 뒤에 dispatch
를 실행하도록 되어있네요.
특히 incrementAsync() 를 살펴보면 dispatch 를 인자로 받는 익명함수를 리턴하고 있다는 것을 확인할 수 있습니다. 이처럼 action
이 아닌 함수를 리턴하는 것이 Redux Thunk 미들웨어를 활용한 비동기 처리라고 할 수 있습니다.
특정한 상태 혹은 조건에 따라 dispatch 를 실행하는 함수를 리턴하는 action creator 의 예제도 있어 아래에 첨부하도록 하겠습니다.
function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
dispatch 와 getState 를 인자로 받아 조건에 따라 dispatch
가 실행되도록 작성된 것을 확인할 수 있습니다.
공식문서를 따라가는 중에 thunk 가 뭔지에 대한 간략한 설명이 있네요.
A thunk is a function that wraps an expression to delay its evaluation.
(thunk 는 표현식을 감싸 계산을 지연시키는 함수이다.)
// calculation of 1 + 2 is immediate
// x === 3
let x = 1 + 2;
// calculation of 1 + 2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1 + 2;
예제 코드로 확인할 수 있듯이, 함수로 어떤 표현식을 감싸게 되면, 그 함수가 불리기 전에는 계산이 실행되지 않죠. 이 때, foo 라는 함수가 바로 thunk 가 된다는 것입니다. 1 + 2 라는 표현식을 익명 함수로 감싸주어 foo() 가 불리기 전에는 계산이 진행되지 않도록 하기 때문에, foo() 는 thunk 가 된다는 것이죠.
thunk 라는 단어 자체는 'think' 라는 단어의 과거형이라고 합니다. 실제로 'think' 의 과거형인건 아니고, 농담삼아 만든 신조어 같은 거라고 하는데요. 즉각적으로 결과를 내놓지 않는다는 점(비동기적)에서 의미가 통하는 부분이 있는 것 같습니다.
Section 2 를 정리하는 HA 가 이틀 앞으로 다가왔습니다. 전체적으로 다시 훑어보다 보니 promise 부분이 약하다는 걸 발견했는데요. 역시나 비동기에 관해서 좀 더 공부가 필요한 것 같습니다. 아무튼 오늘의 TIL 은 여기에서 마치도록 하겠습니다.